library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(ggplot2)
library(forcats)
library(here)
here() starts at /Users/avrilwang/Desktop/Project-Plasmodium
library(deSolve)
library(crone)
library(optimParallel)
Loading required package: parallel
library(doParallel)
Loading required package: foreach
Loading required package: iterators
library(doRNG)
Loading required package: rngtools
library(arrow)

Attaching package: ‘arrow’

The following object is masked from ‘package:utils’:

    timestamp
library(stringr)
library(parallel)
library(ggpubr)
*** recursive gc invocation
*** recursive gc invocation
*** recursive gc invocation

Notebook for plotting all of the figures for PloS Biology manuscript submission

Guidelines: taken from https://journals.plos.org/plosbiology/s/figures#loc-figure-file-requirements 1. format: eps 2. max file size: 10 MB 3. text size: Arial, Times, or Symbol font only in 8-12 point 2. figure size: Width: 789 – 2250 pixels (at 300 dpi). Height maximum: 2625 pixels (at 300 dpi).

#=========================================# figure 1: best single and co-infection cue #=========================================# Figure displaying the reaction norms of best single and co-infection.

#——- optimal cue reaction norm ———–# # read data

process data for reaction norm

# import labelling scheme
ez_label <- read.csv(here("data/ez_label.csv"))

# get si_label with ci cue range
si_ci_rug.df <- ci_rug.df %>% 
  mutate(label_si = case_when(
    label %in% c("I", "I1+I2") ~ "I",
    label %in% c("I log","I1+I2 log") ~ "I log",
    label %in% c("Ig", "Ig1+Ig2") ~ "Ig",
    label %in% c("Ig log") ~ "Ig log",
    label %in% c("sum", "I+Ig") ~ "I+Ig",
    label %in% c("sum log", "I+Ig log") ~ "I+Ig log",
    label == "R" ~ "R",
    label == "R log" ~ "R log",
    label %in% c("G", "G1+G2") ~ "G",
    label == "G log" ~ "G log"
  )) 

# get limit for si_rug
si_rug_lim.df <- si_rug.df %>% 
  filter(time <= 20) %>%
  group_by(label)%>% 
  summarise(min = min(value, na.rm = T)*0.9,
         max = max(value, na.rm = T)*1.1) %>% 
  select(label_si = label, min_si = min, max_si = max)

# filter to restriction conversion rate reaction norm range to cue ranges that appear in rug
## change to Inf/-inf to NA. Note that I am first joining with si rug lim to check which limit is larger, We will go with the cue range that has the largest span
ci_rug_lim.df <- si_ci_rug.df %>% 
  group_by(label) %>% 
  mutate(min = min(value, na.rm = T)*0.9,
         max = max(value, na.rm = T)*1.1) %>% 
  distinct(label, .keep_all = T) %>% 
  select(label, label_si, min, max)

rug_lim.final <- ci_rug_lim.df %>% left_join(si_rug_lim.df, by = "label_si") %>% 
  mutate(final_min = min(min, min_si),
         final_max = max(max, max_si))

# get second rug_lim.final for single infection
rug_lim.final2 <- rug_lim.final %>% 
  group_by(label_si) %>% 
  mutate(final_min = min(final_min, na.rm = T),
         final_max = max(final_max, na.rm = T))

# filter ci_rn by limit
ci_rn.df2 <- ci_rn.df %>% 
  left_join(rug_lim.final, by  = "label") %>% 
  group_by(label) %>% 
  filter(cue_range <= final_max & cue_range >= final_min) %>% 
  arrange(cue_range, .by_group = T) %>% 
  filter(row_number() %% 10 == 0) 
# import labelling scheme
ez_label <- read.csv(here("data/ez_label.csv"))

match single infection rn with coinfection

# get ci label to si rug and filter by limit
si_rn.df2 <- left_join(si_rn.df, select(ez_label, label_si, label_ci), by = c("label" = "label_si")) %>% 
  left_join(rug_lim.final, by  = c("label_ci" = "label")) %>% 
  group_by(label_ci) %>% 
  filter(cue_range <= final_max & cue_range >= final_min) %>% 
  arrange(cue_range, .by_group = T) %>% 
  filter(row_number() %% 10 == 0) %>% 
  select(cue_range, cr, label_ci, label_si)
Warning in left_join(si_rn.df, select(ez_label, label_si, label_ci), by = c(label = "label_si")) :
  Detected an unexpected many-to-many relationship between `x` and `y`.
ℹ Row 1 of `x` matches multiple rows in `y`.
ℹ Row 1 of `y` matches multiple rows in `x`.
ℹ If a many-to-many relationship is expected, set `relationship = "many-to-many"` to silence this warning.
# get ci label to si rug, we will keep one unique value per label
si_rug.df2 <- select(si_rug.df, value, label_si = label) %>% distinct(value, label_si)

plot reaction norm

# join with ezlabel
ci_rn.df3 <- ci_rn.df2 %>% left_join(ez_label, by = c("label" = "label_ci"))
si_rn.df3 <- si_rn.df2 %>% left_join(ez_label, by = "label_ci")
ci_rug.df3 <- ci_rug.df %>% left_join(ez_label, by = c("label" = "label_ci"))
si_rug.df3 <- si_rug.df2 %>% left_join(ez_label, by = "label_si")
Warning in left_join(., ez_label, by = "label_si") :
  Detected an unexpected many-to-many relationship between `x` and `y`.
ℹ Row 27002 of `x` matches multiple rows in `y`.
ℹ Row 12 of `y` matches multiple rows in `x`.
ℹ If a many-to-many relationship is expected, set `relationship = "many-to-many"` to silence this warning.
# redo order of cues
ci_rn.df3$ez_label <- factor(ci_rn.df3$ez_label, 
                              levels = c("Asexual iRBC", "Asexual iRBC log10",
                                         "Total asexual iRBC", "Total asexual\niRBC log10",
                                         "Sexual iRBC", "Sexual iRBC log10",
                                         "Asexual&sexual iRBC", "Asexual&sexual\niRBC log10",
                                         "Total iRBC", "Total iRBC log10",
                                         "Gametocyte", "Gametocyte log10",
                                         "Total gametocyte", "Total sexual iRBC",
                                         "RBC", "RBC log10")) 

si_rn.df3$ez_label <- factor(si_rn.df3$ez_label, 
                              levels = c("Asexual iRBC", "Asexual iRBC log10",
                                         "Total asexual iRBC", "Total asexual\niRBC log10",
                                         "Sexual iRBC", "Sexual iRBC log10",
                                         "Asexual&sexual iRBC", "Asexual&sexual\niRBC log10",
                                         "Total iRBC", "Total iRBC log10",
                                         "Gametocyte", "Gametocyte log10",
                                         "Total gametocyte", "Total sexual iRBC",
                                         "RBC", "RBC log10"))

ci_rug.df3$ez_label <- factor(ci_rug.df3$ez_label, 
                              levels = c("Asexual iRBC", "Asexual iRBC log10",
                                         "Total asexual iRBC", "Total asexual\niRBC log10",
                                         "Sexual iRBC", "Sexual iRBC log10",
                                         "Asexual&sexual iRBC", "Asexual&sexual\niRBC log10",
                                         "Total iRBC", "Total iRBC log10",
                                         "Gametocyte", "Gametocyte log10",
                                         "Total gametocyte", "Total sexual iRBC",
                                         "RBC", "RBC log10"))

si_rug.df3$ez_label <- factor(si_rug.df3$ez_label, 
                              levels = c("Asexual iRBC", "Asexual iRBC log10",
                                         "Total asexual iRBC", "Total asexual\niRBC log10",
                                         "Sexual iRBC", "Sexual iRBC log10",
                                         "Asexual&sexual iRBC", "Asexual&sexual\niRBC log10",
                                         "Total iRBC", "Total iRBC log10",
                                         "Gametocyte", "Gametocyte log10",
                                         "Total gametocyte", "Total sexual iRBC",
                                         "RBC", "RBC log10"))
# plot
ggplot() +
  geom_line(data = ci_rn.df3, aes(x = cue_range, y = cr, color = "Co-infection")) +
  geom_point(data = ci_rn.df3 %>% 
    group_by(label) %>% 
    mutate(ten_th = round(n()/10)) %>% 
    filter(row_number() %% ten_th == 0), aes(x = cue_range, y = cr, color = "Co-infection", shape = "Co-infection"), size = 2) +
  geom_line(data = si_rn.df3, aes(x = cue_range, y = cr, color = "Single infection")) +
  geom_point(data = si_rn.df3 %>% 
    group_by(label_ci) %>% 
    mutate(ten_th = round(n()/10)) %>% 
    filter(row_number() %% ten_th == 0), aes(x = cue_range, y = cr, color = "Single infection", shape = "Single infection"), size = 2) +
  geom_rug(data = ci_rug.df3, aes(x = value), color = "#4575b4", sides = "t", length = unit(0.1, "npc")) +
  geom_rug(data = si_rug.df3, aes(x = value), color = "#fc8d59", sides = "b", length = unit(0.1, "npc")) +
  facet_wrap(~ez_label, scales = "free_x", ncol = 2) +
  ylim(-0.3, 1.3) +
  theme_bw() +
  labs(y = "Conversion rate", x = "Cue range", color = "Model", shape = "Model") +
  scale_x_continuous(labels = function(x) format(x, scientific = T),
                     guide = guide_axis(check.overlap = TRUE)) + 
                    theme(axis.text.x = element_text(size = 7),
                          legend.position = "right")  +
  scale_color_manual(values=c( "#4575b4", "#fc8d59")) +
  theme(strip.text.x = element_text(margin = margin(b = 0.5, t = 0.5)))

ggsave(units = "px", dpi = 300, width = 2000, height = 2500, filename = here("figures/plos-bio/reaction_norm.tiff"), bg = "white", scale = 1.1)

#=========================================# Plotting single and co-infection fitness scatter plot #=========================================# # import in data

# single infection dynamics
si_dyn.df <- read_parquet(here("data/si_dyn/si_dyn_30.parquet")) 

# co-infection dynamics
ci_dyn.df <- read_parquet(here("data/ci_dyn/ci_dyn.parquet"))

ez_label <- read.csv(here("data/ez_label.csv"))

process for final 20 days fitness

plot scatter point of single infection vs co-infection

#=========================================================# # time series conversion rate for single and co-infection #=========================================================# #———get “ideal” single infection and co-infection dynamics———# This is when stuff are optimized based on time

# single infection dynamic with time as cue
si_t.df <- chabaudi_si_clean(
  parameters_cr = c(4.55386, -13.0056, 4.15466, -11.9424),
  immunity = "tsukushi",
  parameters = parameters_tsukushi,
  time_range = seq(0, 20, by = 1e-3),
  cue_range =  seq(0, 20, by = 1e-3),
  cue = "t",
  solver = "vode",
  dyn = T)
# single infection dynamic with time as cue
si_t.df <- chabaudi_si_clean(
  parameters_cr = c(4.55386, -13.0056, 4.15466, -11.9424),
  immunity = "tsukushi",
  parameters = parameters_tsukushi,
  time_range = seq(0, 20, by = 1e-3),
  cue_range =  seq(0, 20, by = 1e-3),
  cue = "t",
  solver = "vode",
  dyn = T)
# co-infection dynamic with time as cue
ci_t.df <- chabaudi_ci_clean(parameters_cr_1 = c(26.16425,  -71.07799,  53.34121,   -166.25693),
                            parameters_cr_2 = c(26.16425,   -71.07799,  53.34121,   -166.25693),
                            immunity = "tsukushi",
                            parameters = parameters_tsukushi,
                            time_range = time_range, 
                            cue_1 =  "t",
                            cue_2= "t",
                            cue_range_1 = time_range, # cue range of strain 1
                            cue_range_2 = time_range, # cue range of strain 2
                            log_cue_1 = "none", # whether to log transform cue 1
                            log_cue_2 = "none", # whether to log transform cue 2
                            solver = "vode", # solver for numerical integration. Vode often gives faster runs
                              dyn = T)
# get only conversion rate and make same format as si_cr.df2/ci_cr.df2
si_t.df %>% filter(time == 20 & variable == "tau_cum") ## fitness value of time as cue in single infection

si_t.cr <- si_t.df %>% 
  filter(variable == "cr") %>% 
  mutate(ez_label_si = "Time", 
         fitness_si =9.787899) %>% 
  select(time, value, fitness_si, ez_label_si)
## get fitness value of co-infection time
ci_t.df %>% filter(time == 20 & variable == "tau_cum1") ## FITNESS VALUE OF TIME AS CUE IN CO-INFECTION
ci_t.cr <- ci_t.df %>% 
  filter(variable == "cr_1") %>% 
  mutate(ez_label = "Time", 
         fitness_ci = 2.311841) %>%
  select(time, value, fitness_ci, ez_label)

#——— single infection conversion rate heat map————–# # process info for single infection

ggplot(data = si_cr.df2, aes(x = time, y = forcats::fct_reorder(ez_label_si, fitness_si))) +
  geom_raster(aes(fill = value)) +
  labs(x = "Time (days)", y = "Single infection cues", fill = "Conversion rate") +
  scale_fill_viridis_c(limits = c(0, 1)) +
  xlim(1, 20) +
  theme_classic()
Warning: Removed 17034 rows containing missing values (`geom_raster()`).

—————–co-infection conversion rate heatmap———–

plot co-infeciton convesion rate heatmap

# get conversion rate dynamics
ci_cr.df <- ci_dyn.df %>% 
  filter(time <= 20 & variable == "cr_1")

# join with classificaiton
ci_cr.df2 <- ci_cr.df %>% 
  left_join(select(ci_fitness.df, label, fitness_ci = value), by = "label") %>% 
  left_join(ez_label, by = c("label" = "label_ci")) %>% 
  select(time, value, fitness_ci, ez_label) %>% 
  rbind(ci_t.cr) # bind time

# plot
ci_cr.pl <- ggplot() +
  geom_raster(data = ci_cr.df2, aes(x = time, y = forcats::fct_reorder(ez_label, fitness_ci), fill = value), alpha = 1) +
  labs(x = "Time (days)", y = "Co-infection cues", fill = "Conversion rate") +
  scale_fill_viridis_c(limits = c(0, 1)) +
  xlim(1, 20) +
  theme_bw()

#——— assemble final figure ————–#

# combine conversion rate dynamic of single infection and co-infection
cr.pl <- ggarrange(si_cr.pl, ci_cr.pl, labels = c("B", "C"), ncol = 2, common.legend = T, align = "h")

# combine with fitness scatterplot
ggarrange(si_ci_fitness.pl, cr.pl, ncol = 1, labels = c("A", ""), align = "hv")

# save
ggsave(units = "px", dpi = 300, width = 2000, height = 2000, filename = here("figures/plos-bio/fitness_cr-dyn.tiff"), bg = "white", scale = 1.35)

#===========================================================# # Demographic stochasticity #===========================================================# #———- plot heat map—————# # import in all fitness files

file_ls <- list.files(path = here("data/MC_partitioned/"), pattern = "*.csv", full.names = T)
name_ls <- list.files(path = here("data/MC_partitioned/"), pattern = "*.csv")
name_ls <- gsub("*.csv", "", name_ls)

# 60, which is about right
length(file_ls)

# read in files
fitness.ls <- lapply(file_ls, read.csv)

# assign unique ID
fitness.ls <- mapply(cbind, fitness.ls, "ID" = name_ls, SIMPLIFY = F)

process data

# get metainfo from ID
fitness.ls2 <- mclapply(fitness.ls, function(x){
  id_col <- x$ID
  # string split to extract all info
  cue <- unlist(str_split(unique(id_col), pattern = "_"))[[3]]
  log <- unlist(str_split(unique(id_col), pattern = "_"))[[4]]
  rand_var <- unlist(str_split(unique(id_col), pattern = "_"))[[5]]
  
  # get mean
  mean_fitness <- mean(x$max_fitness)
  # get sd
  sd_fitness <- sd(x$max_fitness)
  
  # bind results
  res <- cbind(x, cue= cue, log = log, rand_var = rand_var, mean_fitness = mean_fitness, sd_fitness = sd_fitness)
  return(res)
})

Get reference data

reference_ls <- list.files(path = here("data/MC2"), pattern = "*.csv", full.names = T)
reference_name.ls <- gsub("*.csv", "", list.files(path = here("data/MC2/"), pattern = "*.csv"))

# read in the files
reference.ls <- lapply(reference_ls, read.csv)

# assign unique ID
reference.ls <- mapply(cbind, reference.ls, "ID" = reference_name.ls, SIMPLIFY = F)

# get meta data
reference.ls2 <- mclapply(reference.ls, function(x){
  id_col <- x$ID
  # string split to extract all info
  cue <- unlist(str_split(unique(id_col), pattern = "_"))[[2]]
  # get log
  third_col <- unlist(str_split(unique(id_col), pattern = "_"))[[3]]
  log <- ifelse(third_col == "log", "log10", "none")
  
  # get mean
  mean_fitness <- mean(x$max_fitness)
  
  # get sd
  sd_fitness <- sd(x$max_fitness)
  
  # bind results
  res <- cbind(x, cue= cue, log = log, rand_var = "all", ref_mean_fitness = mean_fitness, ref_sd_fitness = sd_fitness)
  return(res)
})

combine MC partitioned and reference df

# get unique column values for each cue, log, and rand_var combo
fitness.ls3 <- do.call(rbind, fitness.ls2)
fitness.ls3 <- fitness.ls3 %>% dplyr::distinct(ID, .keep_all = T)

# repeat with reference
reference.ls3 <- do.call(rbind, reference.ls2)
reference.ls3 <- reference.ls3 %>% dplyr::distinct(ID, .keep_all = T)

# combine!
ref_fit.df <- left_join(fitness.ls3, reference.ls3, by = c("cue" = "cue", "log"= "log"))

compute proportion fitness and variation

ref_fit.df2 <- ref_fit.df %>% 
  mutate(p_sd = sd_fitness/ref_sd_fitness,
         p_mean = ref_mean_fitness/mean_fitness,
         cue_log = paste0(cue, "_", log),
         label = case_when(
           cue == "G" ~ "Gametocyte",
           cue == "I" ~ "Asexual iRBC",
           cue == "I+Ig" ~ "Asexual&sexual\niRBC",
           cue == "Ig" ~ "Sexual iRBC",
           cue == "R" ~ "RBC"
           ),
         parameter = case_when(
           rand_var.x == "rho" ~ "ρ",
           rand_var.x == "phin" ~ "ϕn",
           rand_var.x == "phiw"~ "ϕw",
           rand_var.x == "psin" ~ "ψn",
           rand_var.x == "psiw" ~ "ψw",
           rand_var.x == "beta" ~ "β"
         ))

plot!

# variation
mc_b <- ggplot() +
  geom_tile(data = ref_fit.df2 , aes(x = label, y = parameter, fill = p_sd)) +
  facet_wrap(~log) +
  theme_bw() +
  viridis::scale_fill_viridis() +
  labs(x = "Cue", y = "Parameter randomized", fill = expression(frac(sd("1 parameter randomized"), sd("all parameters randomized")))) +
  theme(legend.position="top",
        axis.text.x = element_text(angle = 45, hjust=1))

# mean fitness
mc_c <- ggplot() +
  geom_tile(data = ref_fit.df2 , aes(x = label, y = parameter, fill = p_mean)) +
  facet_wrap(~log) +
  theme_bw() +
  viridis::scale_fill_viridis() +
  labs(x = "Cue", y = "Parameter randomized", fill = expression(frac(Mean("all parameters randomized"), Mean("1 parameter randomized")))) +
  theme(legend.position="top",
        axis.text.x = element_text(angle = 45, hjust=1))

mc_partition <- ggarrange(mc_b, mc_c, ncol = 1)

#————– get violine plot of variation in fitness ——————–# # read MC data

# read in dymamics
mc_G_log.dyn <- read_parquet(here("data/MC2/mc_G_log_dyn.parquet"))
mc_G.dyn <- read_parquet(here("data/MC2/mc_G_dyn.parquet"))
mc_R_log.dyn <- read_parquet(here("data/MC2/mc_R_log_dyn.parquet"))
mc_R.dyn <- read_parquet(here("data/MC2/mc_R_dyn.parquet"))
mc_I_log.dyn <- read_parquet(here("data/MC2/mc_I_log_dyn.parquet"))
mc_I.dyn <- read_parquet(here("data/MC2/mc_I_dyn.parquet"))
mc_Ig_log.dyn <- read_parquet(here("data/MC2/mc_Ig_log_dyn.parquet"))
mc_Ig.dyn <- read_parquet(here("data/MC2/mc_Ig_dyn.parquet"))
mc_I_Ig_log.dyn <- read_parquet(here("data/MC2/mc_I+Ig_log_dyn.parquet"))
mc_I_Ig.dyn <- read_parquet(here("data/MC2/mc_I+Ig_dyn.parquet"))

# read in fitness
mc_G_log.fitness <- read.csv(here("data/MC2/mc_G_log_fitness.csv"))
mc_G.fitness <- read.csv(here("data/MC2/mc_G_fitness.csv"))
mc_R_log.fitness <- read.csv(here("data/MC2/mc_R_log_fitness.csv"))
mc_R.fitness <- read.csv(here("data/MC2/mc_R_fitness.csv"))
mc_I_log.fitness <- read.csv(here("data/MC2/mc_I_log_fitness.csv"))
mc_I.fitness <- read.csv(here("data/MC2/mc_I_fitness.csv"))
mc_Ig_log.fitness <- read.csv(here("data/MC2/mc_Ig_log_fitness.csv"))
mc_Ig.fitness <- read.csv(here("data/MC2/mc_Ig_fitness.csv"))
mc_I_Ig_log.fitness <- read.csv(here("data/MC2/mc_I+Ig_log_fitness.csv"))
mc_I_Ig.fitness <- read.csv(here("data/MC2/mc_I+Ig_fitness.csv"))

examine variation

# quantify variance and mean
fitness_var.df <- fitness.df %>% 
  dplyr::group_by(id) %>% 
  dplyr::summarise(median = median(max_fitness)) %>% 
  dplyr::mutate(id = forcats::fct_reorder(id, mean))
Error in `mutate_cols()`:
! Problem with `mutate()` column `id`.
ℹ `id = forcats::fct_reorder(id, mean)`.
✖ length(f) == length(.x) is not TRUE
Caused by error in `forcats::fct_reorder()`:
! length(f) == length(.x) is not TRUE
Backtrace:
 1. ... %>% dplyr::mutate(id = forcats::fct_reorder(id, mean))
 7. forcats::fct_reorder(id, mean)
 8. base::stopifnot(length(f) == length(.x))
 9. base::stop(simpleError(msg, call = if (p <- sys.parent(1L)) sys.call(p)))

plot violin with difference in deterministic model fitness and mean model fitness

#————– plot together———————–#

#——————————————–# # dual cue optimization figure #——————————————–#

source(here("functions/chabaudi_si_clean_high.R"))
source(here("functions/chabaudi_si_clean.R"))
source(here("functions/par_to_hm_te.R"))

#———- plotting fitness of dual vs single cue opt ———# # import in previous data

# dual cue fitness
dual_fitness.df <- read.csv(here("data/dual_cue_opt4/dual_cue_fitness_20.csv"))
## make label and filter out very low fitness
dual_fitness.df <- dual_fitness.df %>% 
  mutate(temp_label = gsub("log", "log10", label),
         temp_label_b = gsub("log", "log10", label_b),
         label_final = paste0(temp_label, "+", temp_label_b)) %>% 
  filter(value > 2)

# get single cue fitness
si_dyn.df <- read_parquet(here("data/si_dyn/si_dyn_30.parquet")) 
si_fitness.df <- si_dyn.df %>% 
  filter(variable == "tau_cum" & time == 20)

# join si and dual cue
dual_si_fitness.df <- dual_fitness.df %>% 
  left_join(select(si_fitness.df, id, si_fitness = value), by = "id") %>% 
  left_join(select(si_fitness.df, id_b = id, si_fitness_b = value), by = "id_b") %>% 
  mutate(si_fitness_max = ifelse(si_fitness > si_fitness_b, si_fitness, si_fitness_b),
         dual_label = gsub("log", "log10", paste(label, "+", label_b)))

plot

#———– time series conversion rate ————-# # dynamics simulation of high parameter cues (these serve as reference points)

# best dual cue combo
dual.cr <- chabaudi_si_clean(
  parameters_cr = c(4.446192033,    10.97518275,    1.38762817, 23.3059254, -3.452052371,   -18.0070692,    39.66614226,    -3.545193141,   18.78350799),
  immunity = "tsukushi",
  parameters = parameters_tsukushi,
  time_range = seq(0, 20, by = 1e-3),
  cue_range =  seq(6, 7, by = 1/500),
  cue_range_b = seq(0, log10(6*(10^6)), by = (log10(6*(10^6)))/500),
  cue = "R",
  cue_b = "I",
  log_cue = "log10",
  log_cue_b = "log10",
  solver = "vode",
  dyn = T
)

# when time is used as a cue (high parameter)
time.cr <- chabaudi_si_clean_high(
  parameters_cr = c(9.154314,  -7.570829, -22.506638 ,  3.382405 ,-13.453519 ,-17.011485  , 3.678181, -12.851895 ,-26.115158),
  immunity = "tsukushi",
  parameters = parameters_tsukushi,
  time_range = seq(0, 20, by = 1e-3),
  cue_range =  seq(0, 20, by = 1e-3),
  cue = "t",
  solver = "vode",
  dyn = T)

# when asexual iRBC is used as a cue (high flexibility)
I_high.cr <- chabaudi_si_clean_high(
  parameters_cr = c(1.296675,  3.544034 , 4.907484,  2.174249, -3.238309 ,-5.181614 ,-1.645072 , 1.834302 , 1.581011),
  immunity = "tsukushi",
  parameters = parameters_tsukushi,
  time_range = seq(0, 20, by = 1e-3),
  cue_range =  seq(0, log10(6*(10^6)), by = (log10(6*(10^6)))/5000),
  cue = "I",
  log_cue = "log10",
  solver = "vode",
  dyn = T)

# when asexual iRBC is used as a cue (normal flexibility)
I.cr <- chabaudi_si_clean(
  parameters_cr = c(5.463558,   2.383948,   -17.757281, 4.571835),
  immunity = "tsukushi",
  parameters = parameters_tsukushi,
  time_range = seq(0, 20, by = 1e-3),
  cue_range =  seq(0, log10(6*(10^6)), by = (log10(6*(10^6)))/5000),
  cue = "I",
  log_cue = "log10",
  solver = "vode",
  dyn = T)

# process 
I_high.cr2 <- I_high.cr %>% filter(variable == "cr") %>% mutate(label_new = "I log10 (df=9)") %>% select(-variable)

I.cr2 <- I.cr %>% filter(variable == "cr") %>% mutate(label_new = "I log10 (df=3)") %>% select(-variable)

time_high.cr2 <- time.cr %>% filter(variable == "cr") %>% mutate(label_new = "Ideal (df=9)") %>% select(-variable)

dual.cr2 <- dual.cr %>% filter(variable == "cr") %>% mutate(label_new = "R log10 + I log10 (df=9)") %>% select(-variable)

# combine
dual_cr.df <- rbind(I_high.cr2, I.cr2, time_high.cr2, dual.cr2)

plot

ggplot() +
  geom_line(data = dual_cr.df, aes(color = label_new, x = time, y = value), size = 1) +
  geom_point(data = dual_cr.df %>% filter(time%%1 == 0), aes(color = label_new, x = time, y = value, shape = label_new), size = 3) +
  labs(x = "Time (days)", y = "Conversion rate", color = "Cue", shape = "Cue") +
  xlim(0, 20) +
  scale_color_manual(values = c("#fc8d59","#fdcb44","black", "#4575b4")) +
  theme_bw() +
  theme(legend.position="bottom") +
  guides(color = guide_legend(nrow = 2, byrow = TRUE))
Warning: Removed 3 rows containing missing values (`geom_line()`).
Warning: Removed 3 rows containing missing values (`geom_point()`).

#———— reaction norm heatmap of R log10 + I log10 ————# # process data

max(R_Ig.dyn$Ig) 
[1] 175754.2

plot

# just testing for sexual iRBC vs RBC
ggplot() +
  geom_path(data = R_Ig.dyn, aes(x = Ig, y = log_R), color = "white", arrow = arrow(angle = 30, length = unit(0.1, "inches"))) +
  geom_point(data = R_Ig.dyn %>% filter(row_number() %% 1000 == 1 & time <= 20), aes(x = Ig, y = log_R), color = "white") +
  scale_x_continuous(trans = "log10") +
  xlim(0, 200000) +
  labs(y = "RBC log10", x = "Sexual iRBC log10", fill = "Conversion rate") +
  theme_dark()
Scale for x is already present.
Adding another scale for x, which will replace the existing scale.

save figure for poster

dual_rn.pl2 <- ggplot() +
  geom_raster(data = R_I.hm, aes(x = cue_range_b, y = cue_range, fill = cr)) +
  scale_fill_viridis_c() +
  geom_path(data = R_I.dyn, aes(x = log_I, y = log_R), color = "white", arrow = arrow(angle = 30, length = unit(0.1, "inches"))) +
  geom_point(data = R_I.dyn %>% filter(row_number() %% 1000 == 1 & time <= 20), aes(x = log_I, y = log_R), color = "white") +
  xlim(0.99*min(hablar::s(R_I.dyn$log_I), na.rm = T), 1.01* max(hablar::s(R_I.dyn$log_I), na.rm = T)) +
  ylim(0.99*min(hablar::s(R_I.dyn$log_R), na.rm = T),1.01* max(hablar::s(R_I.dyn$log_R), na.rm = T)) +
  labs(y = "RBC log10", x = "Asexual iRBC log10", fill = "Conversion rate") +
  theme_dark() + theme(legend.position="top") 

dual_cr.pl2 <- ggplot() +
  geom_line(data = dual_cr.df, aes(color = label_new, x = time, y = value), size = 1) +
  geom_point(data = dual_cr.df %>% filter(time%%1 == 0), aes(color = label_new, x = time, y = value, shape = label_new), size = 2) +
  labs(x = "Time (days)", y = "Conversion rate", color = "Cue", shape = "Cue") +
  xlim(0, 20) +
  scale_color_manual(values = c("#4575b4", "#91bfdb","#fc8d59","#fdcb44")) +
  theme_bw() +
  theme(legend.position="top") +
  guides(color = guide_legend(nrow = 2, byrow = TRUE))

ggarrange(dual_cr.pl2, dual_rn.pl2, align = "h", widths = c(1.25, 1))
ggsave(here("poster/dual_cue.png"), width = 7, height = 4)

#——– assemble final figure ————-#

#============================================# # get dual cue disease map (simulated) #============================================# I am going to take the optimal dynamic (R log10 + I log10) and plot all possible disease curves and see if any follow the hysteresis curve. See below for real life disease curve.

#============================================# # real life disease curve #============================================# # execute code from report 10 to get final dataset The following graphs will be made: - R vs iRBC - R log10 vs iRBC - R vs iRBC log10 - R log10 vs iRBC log10

R on y-axis

r_i.dc <- ggplot(exp_ss.df) +
  geom_point(aes(y = RBC, x = asex)) +
  geom_path(aes(y = RBC, x = asex, colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  theme_bw() + 
  scale_color_viridis_c(limits = c(3, 21)) +
  labs(x = "iRBC per µL", y = "RBC per µL", color = "Days\npost-infection") +
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE))

rlog_i.dc <- ggplot(exp_ss.df) +
  geom_point(aes(y = log10(RBC), x = asex)) +
  geom_path(aes(y = log10(RBC), x = asex, colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  theme_bw() + 
  scale_color_viridis_c(limits = c(3, 21)) +
  labs(x = "iRBC per µL", y = "log10(RBC) per µL", color = "Days\npost-infection") +
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE))

r_ilog.dc <-ggplot(exp_ss.df) +
  geom_point(aes(y = RBC, x = log10(asex))) +
  geom_path(aes(y = RBC, x = log10(asex), colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  theme_bw() + 
  scale_color_viridis_c(limits = c(3, 21)) +
  labs(x = "log10(iRBC) per µL", y = "RBC per µL", color = "Days\npost-infection") +
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE))

rlog_ilog.dc <- ggplot(exp_ss.df) +
  geom_point(aes(y = log10(RBC), x = log10(asex))) +
  geom_path(aes(y = log10(RBC), x = log10(asex), colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  theme_bw() + 
  scale_color_viridis_c(limits = c(3, 21)) +
  labs(x = "log10(iRBC) per µL", y = "log10(RBC) per µL", color = "Days\npost-infection") +
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE))

G on y-axis

g_i.dc <- ggplot(exp_ss.df) +
  geom_point(aes(y = gam, x = asex)) +
  geom_path(aes(y = gam, x = asex, colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  theme_bw() + 
  scale_color_viridis_c(limits = c(3, 21)) +
  labs(x = "iRBC per µL", y = "Gametocyte per µL", color = "Days\npost-infection") +
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE))

glog_i.dc <- ggplot(exp_ss.df) +
  geom_point(aes(y = log10(gam), x = asex)) +
  geom_path(aes(y = log10(gam), x = asex, colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  theme_bw() + 
  scale_color_viridis_c(limits = c(3, 21)) +
  labs(x = "iRBC per µL", y = "log10(Gametocyte) per µL", color = "Days\npost-infection") +
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE))

g_ilog.dc <- ggplot(exp_ss.df) +
  geom_point(aes(y = gam, x = log10(asex))) +
  geom_path(aes(y = gam, x = log10(asex), colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  theme_bw() + 
  scale_color_viridis_c(limits = c(3, 21)) +
  labs(x = "log10(iRBC) per µL", y = "Gametocyte per µL", color = "Days\npost-infection") +
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE))

glog_ilog.dc <- ggplot(exp_ss.df) +
  geom_point(aes(y = log10(gam), x = log10(asex))) +
  geom_path(aes(y = log10(gam), x = log10(asex), colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  theme_bw() + 
  scale_color_viridis_c(limits = c(3, 21)) +
  labs(x = "log10(iRBC) per µL", y = "log10(Gametocyte) per µL", color = "Days\npost-infection") +
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE))

R vs G

r_g.dc <- ggplot(exp_ss.df) +
  geom_point(aes(y = RBC, x = gam)) +
  geom_path(aes(y = RBC, x = gam, colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  theme_bw() + 
  scale_color_viridis_c(limits = c(3, 21)) +
  labs(x = "Gametocyte per µL", y = "RBC per µL", color = "Days\npost-infection") +
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE))

rlog_g.dc <- ggplot(exp_ss.df) +
  geom_point(aes(y = log10(RBC), x = gam)) +
  geom_path(aes(y = log10(RBC), x = gam, colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  theme_bw() + 
  scale_color_viridis_c(limits = c(3, 21)) +
  labs(x = "Gametocyte per µL", y = "log10(RBC per µL)", color = "Days\npost-infection") +
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE))

r_glog.dc <- ggplot(exp_ss.df) +
  geom_point(aes(y = RBC, x = log10(gam))) +
  geom_path(aes(y = RBC, x = log10(gam), colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  theme_bw() + 
  scale_color_viridis_c(limits = c(3, 21)) +
  labs(x = "log10(Gametocyte) per µL", y = "RBC per µL", color = "Days\npost-infection") +
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE))

rlog_glog.dc <- ggplot(exp_ss.df) +
  geom_point(aes(y = log10(RBC), x = log10(gam))) +
  geom_path(aes(y = log10(RBC), x = log10(gam), colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  theme_bw() + 
  scale_color_viridis_c(limits = c(3, 21)) +
  labs(x = "log10(Gametocyte) per µL", y = "log10(RBC) per µL", color = "Days\npost-infection") +
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE))

plot together

#===========================================# # static competition #===========================================# #——- heat map —————# # calculate fitness difference for 20 days

static.ls <- lapply(static.ls, read_parquet)
Error: file must be a "InputStream"

import and process data

plot

ggarrange(static.pl1, static.pl2, align = "hv", widths = c(1, 0.2))
Warning: Graphs cannot be vertically aligned unless the axis parameter is set. Placing graphs unaligned.

ggarrange(static.pl1, static.pl2, align = "hv", widths = c(1, 0.2))
Warning: Graphs cannot be vertically aligned unless the axis parameter is set. Placing graphs unaligned.
ggsave(here("figures/plos-bio/static_competition_a.tiff"), units = "px", width = 2250, height = 1500, scale = 1.2, dpi=300,  bg = "white")

#—— effect cue perception ——-# ## logging

# get non-logged pairings
static_nolog <- static.df2 %>% 
  mutate(cue_1 = trimws(gsub("\\ .*", "", label_ci_1)),
         log_1 = case_when(
           str_detect(label_ci_1, "log") ~ "log",
           str_detect(label_ci_1, "log", negate = T) ~ "none")) %>% 
  filter(log_1 == "none")

static_log <- static.df2 %>% 
  mutate(cue_1 = trimws(gsub("\\ .*", "", label_ci_1)),
         log_1 = case_when(
           str_detect(label_ci_1, "log") ~ "log",
           str_detect(label_ci_1, "log", negate = T) ~ "none")) %>% 
  filter(log_1 == "log")

static_log.df <- left_join(
  select(static_nolog, cue_1, label_ci_2, log_1, None = fitness_difference),
  select(static_log, cue_1, label_ci_2, log_1, Log = fitness_difference),
  by = c("cue_1", "label_ci_2")) %>% 
  filter(!is.na(None) & !is.na(Log)) %>% 
  mutate(classification = ifelse(Log > None, "Logged better", "Not logged better"))

combined

static_nocomb <- static.df2 %>% 
  mutate(cue_1 = ifelse(
    str_detect(label_ci_1, "sum"), "I+Ig",
    trimws(gsub("+1.*|\\ log", "", label_ci_1))
  ),
  log_1 = case_when(
           str_detect(label_ci_1, "log") ~ "log",
           str_detect(label_ci_1, "log", negate = T) ~ "none"),
    comb_1 = case_when(
    str_detect(label_ci_1, "1+|sum") ~ "comb",
    str_detect(label_ci_1, "1+|sum", negate = T) ~ "none" 
  )) %>% 
  filter(comb_1 == "none")

static_comb <- static.df2 %>% 
  mutate(cue_1 = ifelse(
    str_detect(label_ci_1, "sum"), "I+Ig",
    trimws(gsub("+1.*|\\ log", "", label_ci_1))
  ),
  log_1 = case_when(
           str_detect(label_ci_1, "log") ~ "log",
           str_detect(label_ci_1, "log", negate = T) ~ "none"),
    comb_1 = case_when(
    str_detect(label_ci_1, "1+|sum") ~ "comb",
    str_detect(label_ci_1, "1+|sum", negate = T) ~ "none" 
  )) %>% 
  filter(comb_1 == "comb")
  
static_comb.df <- left_join(
  select(static_nocomb, cue_1, label_ci_2, log_1, Self = fitness_difference),
  select(static_comb, cue_1, label_ci_2, log_1, Total = fitness_difference),
  by = c("cue_1", "log_1", "label_ci_2")) %>% 
  filter(!is.na(Total) & !is.na(Self)) %>% 
  mutate(classification = ifelse(Total > Self, "Total better", "Self better"))

plot

ggarrange(static_log.pl, static_comb.pl, ncol = 1, nrow = 2, align = "v")
ggarrange(static_log.pl, static_comb.pl, ncol = 1, nrow = 2, align = "v")

ggsave(here("figures/plos-bio/static_competition_b.tiff"), units = "px", width = 1000, height = 2000, scale = 1.2, dpi=300,  bg = "white")

#===========================================# # invasion analysis #===========================================# # import in data (already 20 days )

invade.df <- read.csv(here("data/ci_invasion.csv"))

process data for invasion matrix

invade.mat <- invade.df %>% 
  group_by(V1 = pmin(mut_id, res_id), V2 = pmax(mut_id, res_id)) %>% # group by cue competition, irregardless of order
  mutate(id_alt = paste0(V1, V2),
         invade = case_when(
           fitness > 0 ~ "invade",
           fitness < 0 ~ "not invade"
         )) %>% 
  group_by(id_alt) %>% 
  mutate(
    mut_is_V1 = case_when(
    mut_id == V1 ~ "V1_invade",
    mut_id != V1 ~ "V1_invaded")) %>% 
  arrange(id_alt) %>% 
  select(fitness, V1, V2, id_alt, invade, mut_is_V1) %>% 
  tidyr::pivot_wider(names_from = mut_is_V1, values_from = fitness) %>% 
  group_by(id_alt) %>% 
  mutate(V1_invade2 = gsub("NA", "", paste0(V1_invade, collapse = "")),
         V1_invaded2 = gsub("NA", "", paste0(V1_invaded, collapse = ""))) %>% 
  distinct(id_alt, .keep_all = T) %>% 
  mutate(
    category = case_when(
    V1_invade2 > 0 & V1_invaded2 > 0 ~ "Mutual invasion",
    V1_invade2 > 0 & V1_invaded2 < 0 ~ "Only strain 1 invasion",
    V1_invade2 < 0 & V1_invaded2 > 0 ~ "Only strain 2 invasion",
    V1_invade2 < 0 & V1_invaded2 < 0 ~ "Mutual non-invasion"
  )) %>% 
  select(V1, V2, invasion = category)

invade.df %>% filter(mut_id == "G-i_none")
invade.df %>% filter(res_id == "G-i_none")
invade.mat4 <- rbind(
  select(invade.mat3, V1_label, V2_label, invasion),
  select(invade.mat3, V2_label = V1_label, V1_label = V2_label) %>% mutate(invasion = NA)) %>%
  mutate(
    invasion_2 = case_when(
    invasion == "Mutual invasion" ~ "Mutual invasion",
    invasion == "Only strain 1 invasion" ~ "Competitive exclusion\nof another cue",
    invasion == "Only strain 2 invasion" ~ "Competitive exclusion\nby another cue"
  )) %>% 
  filter(!is.na(V1_label))
Adding missing grouping variables: `id_alt`
Adding missing grouping variables: `id_alt`

plot invasion matrix

create summary bar chart

# create a stacked barchart for summary
## filter out na
invade.matalt <- invade.mat3 %>% na.exclude()

# get frquency from both sides. Note when grouping for V2, from the perspective of cue 2, scenarrio when strain 2 invade = strain 1 invade
invade.matalt1 <- invade.matalt %>% group_by(V1_label, invasion) %>% 
  summarize(frequency_1 = n())

invade.matalt2 <- invade.matalt %>%
  mutate(invasion_alt = case_when(
    invasion == "Only strain 1 invasion" ~ "Only strain 2 invasion",
    invasion == "Only strain 2 invasion" ~ "Only strain 1 invasion",
    invasion == "Mutual invasion" ~ "Mutual invasion",
    invasion == "Mutual non-invasion" ~ "Mutual non-invasion"
  )) %>% 
  group_by(V2_label, invasion_alt) %>% 
  summarize(frequency_2 = n())     

# full join and sum. has confirmed all of them add up to 14 
invade.matalt3 <- full_join(invade.matalt1, invade.matalt2, by = c("V1_label" = "V2_label", "invasion" = "invasion_alt"))

invade.matalt3[is.na(invade.matalt3)] <- 0
invade.matalt4 <- invade.matalt3 %>% 
  mutate(freq = frequency_1 + frequency_2) %>% 
  mutate(temp = case_when(
    invasion == "Only strain 1 invasion" ~ freq
  )) %>% 
  group_by(V1_label) %>% 
  mutate(invade_1_freq = max(temp, na.rm = T)) %>% 
  mutate(invasion_2 = case_when(
    invasion == "Mutual invasion" ~ "Mutual invasion",
    invasion == "Only strain 1 invasion" ~ "Competitive exclusion\nof another cue",
    invasion == "Only strain 2 invasion" ~ "Competitive exclusion\nby another cue"
  ))

plot together

ggarrange(invasion.pl1, invasion.pl2, align = "h", common.legend = T, widths = c(2, 1))

ggarrange(invasion.pl1, invasion.pl2, align = "h", common.legend = T, widths = c(2, 1))
ggsave(here("figures/plos-bio/invasion_a.tiff"), units = "px", width = 2250, height = 1100, scale = 1.4, dpi=300,  bg = "white")

#—————- invasion pairwise comparison—————–# ## proces data

log

combined

invade_nocomb <- invade.df2 %>% 
  mutate(cue_1 = ifelse(
    str_detect(label_ci_1, "sum"), "I+Ig",
    trimws(gsub("+1.*|\\ log", "", label_ci_1))
  ),
  log_1 = case_when(
           str_detect(label_ci_1, "log") ~ "log",
           str_detect(label_ci_1, "log", negate = T) ~ "none"),
    comb_1 = case_when(
    str_detect(label_ci_1, "1+|sum") ~ "comb",
    str_detect(label_ci_1, "1+|sum", negate = T) ~ "none" 
  )) %>% 
  filter(comb_1 == "none")

invade_comb <- invade.df2 %>% 
  mutate(cue_1 = ifelse(
    str_detect(label_ci_1, "sum"), "I+Ig",
    trimws(gsub("+1.*|\\ log", "", label_ci_1))
  ),
  log_1 = case_when(
           str_detect(label_ci_1, "log") ~ "log",
           str_detect(label_ci_1, "log", negate = T) ~ "none"),
    comb_1 = case_when(
    str_detect(label_ci_1, "1+|sum") ~ "comb",
    str_detect(label_ci_1, "1+|sum", negate = T) ~ "none" 
  )) %>% 
  filter(comb_1 == "comb")
  
invade_comb.df <- left_join(
  select(invade_nocomb, cue_1, res_id, log_1, Self = fitness),
  select(invade_comb, cue_1, res_id, log_1, Total = fitness),
  by = c("cue_1", "log_1", "res_id")) %>% 
  filter(!is.na(Total) & !is.na(Self)) %>% 
  mutate(classification = ifelse(Total > Self, "Total better", "Self better"))
invade_comb.df

plot

ggarrange(invade_log.pl, invade_comb.pl, align = "h", ncol = 2)
ggarrange(invade_log.pl, invade_comb.pl, align = "h", ncol = 2)

ggsave(here("figures/plos-bio/invasion_b.tiff"), units = "px", width = 2250, height = 850, scale = 1.2, dpi=300,  bg = "white")

#===========================================# # Cue performance across single, co-infection, static, and invasion #===========================================#

plot

#-=====================# # Partitioning best cue #=====================-# #——- single infection ———–# # redo some optimization (lower fitness in no R than default)

source(here("functions/chabaudi_si_clean_R.R"))
source(here("functions/chabaudi_si_clean_N.R"))
# I none
cl <- makeCluster(detectCores()); setDefaultCluster(cl = cl)
I_no_R <- optimParallel(
    par = rep(0.5,4), # start at 0.5x4
    fn = chabaudi_si_clean_R, 
    control = list(trace = 6, fnscale = -1),
    immunity = "tsukushi",
    parameters = parameters_tsukushi,
    time_range = seq(0, 20, by = 1e-3),
    cue_range =  seq(0, 6*(10^6), by = (6*(10^6))/5000),
    cue = "I",
    log_cue = "none",
    solver = "vode")
stopCluster(cl)
# 0.144021 -43.1046 2030.27 -524.686 
# 8.69589

import and process data

# import in data
si_partition.ls <- list.files(path = here("data/partition/si/"), pattern = "*.csv", full.names = T)
si_partition.ls <- lapply(si_partition.ls, read.csv)
si_partition.df <- do.call(rbind, si_partition.ls)

# combine with si fitness (default)
si_partition.df <- si_partition.df %>% left_join(select(si_fitness.df, id, fitness = value), by = "id")

# make longer
si_partition.df2 <- tidyr::pivot_longer(si_partition.df, c(fitness_R, fitness_N, fitness_W, fitness))

# calculate coefficient of variation. Also rename
si_partition.df2 <- si_partition.df2 %>% 
  group_by(name) %>% 
  mutate(cv = sd(value)/mean(value)*100,
         mean = mean(value),
         category = case_when(
           name == "fitness_R" ~ "No RBC limitation",
           name == "fitness_W" ~ "No targeted immunity",
           name == "fitness_N" ~ "No indiscriminate\nimmunity",
           name == "fitness" ~ "Default"
         ))

plot

library(ungeviz)
# raw fitness
si_partition.pl1 <- ggplot() +
  geom_vpline(data = si_partition.df2, aes(y = fct_reorder(category, mean), x = mean, group = category, color = category), show.legend = F, size = 1) +
  geom_point(data = si_partition.df2, aes(y = fct_reorder(category, mean), x = value), size = 2, alpha = 0.7) +
  geom_line(data = si_partition.df2, aes(y = fct_reorder(category, mean), x = value, group = id), alpha = 0.2) +
  labs(x = "Fitness", y = "Conditions") +
  theme_bw()

# coefficient of variation
si_partition.pl2 <- ggplot() +
  geom_bar(data = si_partition.df2, aes(y = fct_reorder(category, mean), x = cv), stat = "identity") +
  labs(x = "Coefficient of\nvariation (%)", y = "") +
  theme_bw() +
  theme(axis.title.y=element_blank(),
        axis.text.y=element_blank(),
        axis.ticks.y=element_blank())

si_partition.pl <- ggarrange(si_partition.pl1, si_partition.pl2, widths = c(1, 0.3), align = "h")
si_partition.pl

ggsave(here("figures/plos-bio/partition_fitness.tiff"), width = 7, height = 4)

#——- consequences of no targeted immunity ————# # get dynamics of no targeted immunity

get_dyn <- function(df){
  
  source(here("functions/chabaudi_si_clean_W.R"))
  id <- df$id
  cue <- df$cue
  log <- df$log
  par <- c(df$var_W1, df$var_W2, df$var_W3, df$var_W4)
  cue_range <- seq(df$low, df$high, by = df$by)
  
  # get dynamics
  dyn <- chabaudi_si_clean_W(
    parameters_cr = par,
    immunity = "tsukushi",
    parameters = parameters_tsukushi,
    time_range = seq(0, 20, by = 1e-3),
    cue_range =  cue_range,
    cue = cue,
    log_cue = log,
    solver = "vode",
    dyn = T
  )
  
  # combine
  dyn2 <- cbind(dyn, id = id, cue = cue, log = log)
  
  write_parquet(dyn2, paste0(here("data/partition/si_dyn/"), id, "_noW_dyn.parquet"))
  
}

get df to run

# join with cue_range
cue_range_si.df <- read.csv(here("data/cue_range_si.csv"))
si_partition.df3 <- si_partition.df %>% left_join(select(cue_range_si.df, low, high, by, id), "id")

# lapply loop
si_partition.ls <- split(si_partition.df3, seq(nrow(si_partition.df3)))
mclapply(si_partition.ls, get_dyn)

process dataframe

# import in dataframe
no_W.ls <- list.files(here("data/partition/si_dyn/"), pattern = "*noW_dyn.parquet", full.names = T)
no_W.df <- lapply(no_W.ls, read_parquet)
no_W.df <- do.call(rbind, no_W.df)

# combine with ez label
ez_label <- read.csv(here("data/ez_label.csv"))
no_W.df <- left_join(no_W.df, ez_label, by = c("id" = "id_si"))

# get conversion rate 
no_W.cr <- no_W.df %>% filter(variable == "cr")
no_W.I <- no_W.df %>% filter(variable == "I")

# get default conversion rate dynamics
si_dyn.df <- left_join(si_dyn.df, ez_label, by = c("id" = "id_si"))
si_dyn.cr <- si_dyn.df %>% filter(variable == "cr")
si_dyn.I <- si_dyn.df %>% filter(variable == "I")

plot conversion rate

mechanism: targeted immunity led to lower parasite density in the initial stages, which prevents parasites from making the switch from no conversion rate to high conversion rate. When parsite density undergoes drastic increase at the beginning due to lower immunity, this presents a higher degree of signal that allows parasite to make the switch appropriately

partition_cr.pl <- ggplot() +
  geom_line(data = no_W.cr, aes(x = time, y= value, color = "No targeted immunity")) +
  geom_line(data = si_dyn.cr, aes(x = time, y= value, color = "Default")) +
  facet_wrap(~ez_label_si, ncol = 5) +
  xlim(0, 20) +
  geom_vline(xintercept = 7) +
  labs(x = "Time (days)", y = "Conversion rate", color = "Condition") +
  theme_bw()

no_W.cr

#—– cue state ————–#

function to get cue states

# function to get cue states
get_cue_state <- function(df){
  cue <- trimws(gsub("_log|_none", "", unique(df$id)))
  if(cue != "I+Ig"){
  df2 <- df %>% filter(variable == cue)
  if(str_detect(unique(df$id), "log")){
    df2 <- df2 %>% 
      mutate(value = log10(value))
  }
  }
  
  if(cue == "I+Ig"){
    df2 <- df %>% filter(variable %in% c("I", "Ig")) %>% 
      group_by(time) %>% 
      mutate(value = sum(value))
    
    if(str_detect(unique(df$id), "log")){
    df2 <- df2 %>% 
      mutate(value = log10(value))
  }
  }
  
  df2$value[df2$value == -Inf] <- 0
  
  write_parquet(df2, paste0(here("data/partition/si_default_state/"), unique(df$id), "_noW_state.parquet"))
}

run function

# split dynamics based on id
no_W.split <- split(no_W.df, no_W.df$id)

# run function
mclapply(no_W.split, get_cue_state)

# get dataframe
no_W.state <- list.files(here("data/partition/si_state/"), pattern = "*.parquet", full.names = T)
no_W.state <- lapply(no_W.state, read_parquet)
no_W.state <- do.call(rbind, no_W.state)
no_W.state$value[no_W.state$value < 0] <- 0

# get same for si infection
default.split <- split(si_dyn.df, si_dyn.df$id)
mclapply(default.split, get_cue_state)
default.state <- list.files(here("data/partition/si_default_state/"), pattern = "*.parquet", full.names = T)
default.state <- lapply(default.state, read_parquet)
default.state <- do.call(rbind, default.state)
default.state$value[default.state$value < 0] <- 0

# manually correct non-logging
I_Ig.corr <- no_W.state %>% filter(id == "I+Ig_log") %>% 
  mutate(value = log10(value))
I_Ig.corr$value[I_Ig.corr$value < 0] <- 0

no_W.state2 <- no_W.state %>% filter(id != "I+Ig_log")
no_W.state2 <- no_W.state2 %>% rbind(no_W.state2, I_Ig.corr)

plot

absence of targeted immunity led to drastic increase in parasite density in early phases of infection. This produces high signal intensity for parasite and host-based cues, especially non-logged ones, which allows for state differentation. While this can be viewed as a modelling artifiact, it should be noted that the logged cues seldom changed as these changes in early infection did little to alter the actual early signal intensity sensed by the parasite. In an environment where there is heterogeneity in host response, and thus, signal, logging allows for parasites to adapt optimal strategy whereas non-logged cues must contend with sensitivity to immunity.

# function to individually plot stuff
plot_state <- function(df1, df2){
  
  # plot state dynamics
  state_pl <- ggplot() +
  geom_line(data = df1, aes(x = time, y = value, color = name, group = name)) +
  facet_wrap(~ez_label_si, scales = "free") +
  xlim(1,20) +
  theme_bw() +
  theme(legend.position="none") +
  labs(x = "", y = "Cue") +
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE)) +
  scale_color_manual(values =c("Default" = "#4575b4", "No targeted\nimmunity" = "#fc8d59"))
  
  # plot conversion rate dynamics
  cr_pl <- ggplot() +
  geom_raster(data = df2, aes(x = time, y = name, fill = value)) +
  xlim(1,20) +
  theme_bw() +
    labs(x = "Time (days)") +
  theme(axis.title.y=element_blank(),
        axis.ticks.y=element_blank(),
        legend.position = "none") +
    scale_fill_viridis_c(lim = c(0, 1))
  
  # arrange
  ggarrange(state_pl, cr_pl, ncol = 1, nrow = 2, align = "v", heights = c(1, 0.4))
  ggsave(paste0(here("figures/plos-bio/partition/"), unique(df1$id), ".tiff"), width = 4.5, height = 3.5)
}

split

# combine state
noW_default.state <- left_join(
  select(no_W.state2, time, `No targeted\nimmunity` = value, id, ez_label_si), 
  select(default.state %>% filter(time <= 20), time, `Default` = value, id, ez_label_si), by = c("time", "id", "ez_label_si"))

noW_default.state2 <- tidyr::pivot_longer(noW_default.state, c(`No targeted\nimmunity`, `Default`))
# combine conversion raster
noW_default.cr <- left_join(
  select(no_W.cr, time, `No targeted\nimmunity` = value, id, ez_label_si), 
  select(si_dyn.cr %>% filter(time <= 20), time, `Default` = value, id, ez_label_si), by = c("time", "id", "ez_label_si"))
noW_default.cr2 <- tidyr::pivot_longer(noW_default.cr, c(`No targeted\nimmunity`, `Default`))

# split
noW_default_state.ls <- split(noW_default.state2, noW_default.state2$id)
noW_default_cr.ls <- split(noW_default.cr2, noW_default.cr2$id)

# run function
mapply(plot_state, noW_default_state.ls, noW_default_cr.ls)

#——– reaction norms of default vs optimized ————# # get reaction norm and rug data

source(here("functions/par_to_df.R"))

# Gametocyte
g_log.rn <- par_to_df(par = c(1.211521, -3.936778,  -1.312944,  -1.285713), cue_range = seq(0, log10(6*(10^4)), by = (log10(6*(10^4)))/5000))
g_log.rn2 <- par_to_df(par = c(1.393860539, -4.253007616,   -0.313947029,   -2.000857344), cue_range = seq(0, log10(6*(10^4)), by = (log10(6*(10^4)))/5000))

g.rn <- par_to_df(par = c(0.04061288,   -9.31445958,    74.13015506,    -431.5984364), cue_range = seq(0, 6*(10^4), by = (6*(10^4))/5000))
g.rn2 <- par_to_df(par = c(0.541729073, -3.904616443,   0.87487412, -0.694177021), cue_range = seq(0, 6*(10^4), by = (6*(10^4))/5000))

# I+Ig
I_Ig_log.rn <- par_to_df(par = c(3.594042,  4.157744,   -13.530672, 2.599905), cue_range = seq(0, log10(6*(10^6)), by = (log10(6*(10^6)))/5000))
I_Ig_log.rn2 <- par_to_df(par = c(63.71893822,  -87.77671601,   -56.55475514,   -66.02209549), cue_range = seq(0, log10(6*(10^6)), by = (log10(6*(10^6)))/5000))

I_Ig.rn <- par_to_df(par = c(0.3159297, -46.1104558,    1250.752908,    -6.1982093), cue_range = seq(0, 6*(10^6), by = (6*(10^6))/5000))
I_Ig.rn2 <- par_to_df(par = c(0.731982784,  -21.69799449,   149.7841876,    17.02551769), cue_range = seq(0, 6*(10^6), by = (6*(10^6))/5000))

# convert log to non-logged scale
g_log.rn$cue_range <- 10^(g_log.rn$cue_range)
g_log.rn2$cue_range <- 10^(g_log.rn2$cue_range)
I_Ig_log.rn$cue_range <- 10^(I_Ig_log.rn$cue_range)
I_Ig_log.rn2$cue_range <- 10^(I_Ig_log.rn2$cue_range)

# get rug
g_log.rug <- default.state %>% 
  filter(label_si == "G log") %>% 
  mutate(value = 10^value) %>% 
  select(label_si, value)

g_log.rug2 <- no_W.state %>% 
  filter(label_si == "G log") %>% 
  mutate(value = 10^value) %>% 
  filter(value <= 6*(10^4)) %>% 
  select(label_si, value)

I_Ig_log.rug <- default.state %>% 
  filter(label_si == "I+Ig log") %>% 
  select(label_si, value)

I_Ig_log.rug2 <- no_W.state %>% 
  filter(label_si == "I+Ig log") %>% 
  select(label_si, value)

g.rug <- default.state %>% 
  filter(label_si == "G") %>% 
  select(label_si, value)

g.rug2 <- no_W.state %>% 
  filter(label_si == "G" & value <= 6*(10^4)) %>% 
  select(label_si, value)

I_Ig.rug <- default.state %>% 
  filter(label_si == "I+Ig") %>% 
  select(label_si, value)

I_Ig.rug2 <- no_W.state %>% 
  filter(label_si == "I+Ig") %>% 
  select(label_si, value)

# get rug limits
rug_lim <- rbind(g_log.rug,
                 g_log.rug2,
                 I_Ig_log.rug,
                 I_Ig_log.rug2,
                 g.rug,
                 g.rug2,
                 I_Ig.rug,
                 I_Ig.rug2) %>% 
  group_by(label_si) %>% 
  summarize(max = max(hablar::s(value), na.rm = T),
            min = min(hablar::s(value), na.rm = T))

# combine and filter
rn <- rbind(
  cbind(g_log.rn, label_si = "G log", condition = "Default"),
  cbind(g_log.rn2, label_si = "G log", condition = "No targeted\nimmunity"),
  cbind(g.rn, label_si = "G", condition = "Default"),
  cbind(g.rn2, label_si = "G", condition = "No targeted\nimmunity"),
  cbind(I_Ig_log.rn, label_si = "I+Ig log", condition = "Default"),
  cbind(I_Ig_log.rn2, label_si = "I+Ig log", condition = "No targeted\nimmunity"),
  cbind(I_Ig.rn, label_si = "I+Ig", condition = "Default"),
  cbind(I_Ig.rn2, label_si = "I+Ig", condition = "No targeted\nimmunity")
) %>% 
  left_join(rug_lim, by = "label_si") %>% 
  group_by(label_si) %>% 
  filter(cue_range <= max & cue_range >= min)

# combine rug
rug <- rbind(cbind(g_log.rug, condition = "Default"),
             cbind(g_log.rug2, condition = "No targeted\nimmunity"),
             cbind(g.rug, condition = "Default"),
             cbind(g.rug2, condition = "No targeted\nimmunity"),
             cbind(I_Ig_log.rug, condition = "Default"),
             cbind(I_Ig_log.rug2, condition = "No targeted\nimmunity"),
             cbind(I_Ig.rug, condition = "Default"),
             cbind(I_Ig.rug2, condition = "No targeted\nimmunity"))

# cobine with ezlabel
rn2 <- rn %>% left_join(ez_label, by = "label_si")
rug2 <- rug %>% left_join(ez_label, by = "label_si")

# filter rug
default.rug <- rug2 %>% filter(condition == "Default")
no.rug <- rug2 %>% filter(condition == "No targeted\nimmunity")

plot

ggplot() +
  geom_line(data = rn2, aes(x = cue_range, y = cr, color = condition)) +
  geom_rug(data = default.rug, aes(x = value, color = condition), sides = "b") +
  geom_rug(data = no.rug, aes(x = value, color = condition), sides = "t") +
  facet_wrap(~fct_relevel(ez_label_si, c("Gametocyte log10", "Gametocyte", "Asexual&sexual\niRBC log10", "Asexual&sexual iRBC")), scales = "free_x") +
  scale_x_continuous(labels = function(x) format(x, scientific = TRUE)) +
  theme_bw() +
  scale_color_manual(values =c("Default" = "#4575b4", "No targeted\nimmunity" = "#fc8d59")) +
  ylim(0, 1.1) +
  labs(x = "Cue range", y = "Conversion rate", color = "Condition")

ggsave(here("figures/plos-bio/partition_rn.tiff"), width = 7.5, height = 6)

get conversion rate legend

noW_default.cr %>% filter(id == "G_log") %>% 
ggplot() +
  geom_raster(aes(x = time, y = id, fill = Default)) +
  xlim(1,20) +
  theme_bw() +
    labs(x = "Time (days)",
         fill = "Conversion rate") +
  theme(axis.title.y=element_blank(),
        axis.ticks.y=element_blank(),) +
    scale_fill_viridis_c(lim = c(0, 1))

ggsave(here("figures/plos-bio/cr_legend.tiff"))

#================================# # Disease curves for single, co-infection, and invasion #===============================# # get data for disease curves

# single infection dynamics
si_dyn.df <- read_parquet(here("data/si_dyn/si_dyn_30.parquet")) 

# co-infection dynamics (mon-cue)
ci_dyn.df <- read_parquet(here("data/ci_dyn/ci_dyn.parquet"))

# dual cue dynamics
dual_dyn.df <- read_parquet(here("data/dual_cue_dyn/dual_cue_dyn.parquet"))

#——- single cue comparison —————# # process data

# process dynamics -> turn skinny
si_dc.df <- si_dyn.df %>% 
  filter(variable == "I" | variable == "Ig" | variable == "R") %>% 
  tidyr::pivot_wider(names_from = variable, values_from = value) %>% 
  mutate(total = I+Ig)
# process dynamics -> turn skinny
si_dc.df <- si_dyn.df %>% 
  filter(variable == "I" | variable == "Ig" | variable == "R") %>% 
  tidyr::pivot_wider(names_from = variable, values_from = value) %>% 
  mutate(total = I+Ig)

plot

#———- co-infection monocue ————-#

# get relevent variables
ci_dc.df <- ci_dyn.df %>% 
  filter(variable == "I1" | variable == "Ig1" | variable == "R")

# morph into skinny format
ci_dc.df <- tidyr::pivot_wider(ci_dc.df, names_from = variable, values_from = value, id_cols = c(time, label)) %>% 
  mutate(total = I1+Ig1)

# good cue bad cue
ci_cue.dv <- ci_fitness.df %>% 
  mutate(classification = case_when(
    value > 2.25 ~ "High-performing",
    value <= 2.25 ~ "Poor-performing"
  ))

# join with classificaiton
ci_dc.df2 <- ci_dc.df %>% left_join(ci_cue.dv, by = "label")

# split into top erforming and poor-performing cues
ci_dc.high <- ci_dc.df2 %>% filter(classification == "High-performing")
ci_dc.poor <- ci_dc.df2 %>% filter(classification == "Poor-performing")

# join high performing with label
ci_dc.high2 <- ci_dc.high %>% left_join(ez_label, by = c("label" = "label_ci"))

#write_parquet(ci_dc.high2, here("data/disease_curve/ci_dc_high.parquet"))
#write_parquet(ci_dc.poor, here("data/disease_curve/ci_dc_poor.parquet"))

plot

ci_dc.poor <- read_parquet(here("data/disease_curve/ci_dc_poor.parquet"))
ci_dc.high2 <- read_parquet(here("data/disease_curve/ci_dc_high.parquet"))

# plot
ci_dc.pre <- ggplot() +
  geom_path(data = ci_dc.poor, aes(x= total, y = R, group = label), color = "dark grey", arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  labs(color = "Co-infection\ngood performing cues", x = "Asexual & sexual iRBC per µL", y = "RBC per µL") +
  theme_bw()+ scale_y_continuous(labels = function(x) format(x, scientific = TRUE, accuracy = 0.1)) +
  guides(shape = FALSE)

ci_dc.pl <- ci_dc.pre +
  geom_point(data = ci_dc.high2 %>% filter(row_number() %% 1000 ==0), aes(x = total, y = R, color = ez_label, shape = ez_label), size = 3) +
  geom_path(data = ci_dc.high2, aes(x= total, y = R, group = ez_label, color = ez_label), size = 1, arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  scale_color_manual(values=c( "#4575b4", "#fc8d59", "#fdcb44", "#91bfdb")) +
  guides(color = guide_legend(override.aes = list(size = 0.1)))

#——— dual cue ————————–# # process data

plot

dual_dc.high <- read_parquet(here("data/disease_curve/dual_dc_high.parquet"))
dual_dc.poor <- read_parquet(here("data/disease_curve/dual_dc_poor.parquet"))

dual_dc.high2 <- dual_dc.high %>% 
  filter(label_alt == "R log10 + I log10")

# add 
dual_dc.pre <- ggplot() +
  geom_path(data = dual_dc.poor, aes(x= total, y = R, group = label_alt), color = "dark grey", arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  labs(color = "High-performing\ndual cues per µL", x = "Asexual & sexual iRBC", y = "RBC per µL") +
  theme_bw()+ scale_y_continuous(labels = function(x) format(x, scientific = TRUE, accuracy = 0.1)) +
  guides(shape = FALSE)


dual_dc.pl <- dual_dc.pre +
  geom_point(data = dual_dc.high2 %>% filter(row_number() %% 1000 ==0), aes(x = total, y = R, shape = label_alt), color = "#4575b4", size = 3) +
  geom_path(data = dual_dc.high2, aes(x= total, y = R, group = label_alt), color = "#4575b4", size = 1, arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  theme(legend.position = "none") +
  guides(color = guide_legend(override.aes = list(size = 0.1)))

#——— co-infection static —————-#

# import in dynamics data
static_dyn.ls <- list.files(path = here("data/ci_static/"), pattern = "*.parquet", full.names = T)
static_dyn.ls <- lapply(static_dyn.ls, read_parquet)

# filter variable and transform
static_dyn.ls2 <- mclapply(static_dyn.ls, function(x){
  x %>% 
    filter(variable == "I1" | variable == "Ig1" | variable == "I2" | variable == "Ig2" | variable == "R") %>% 
    mutate(id_alt = paste(id_1, id_2)) %>% 
    tidyr::pivot_wider(names_from = variable, values_from = value, id_cols = c(time, id_alt)) %>%
  mutate(total1 = I1+Ig1, total2 = I2+Ig2)
})

static_dc.df <- do.call(rbind, static_dyn.ls2)
static_dc.df <- static_dc.df %>% 
  mutate(id_1 = gsub(" .*", "", id_alt),
         id_2 = gsub(".* ", "", id_alt)) %>% 
  filter(id_1 != id_2)
#write_parquet(static_dc.df, here("data/disease_curve/static_dc.parquet"))

further processing

static_dc.df <- read_parquet(here("data/disease_curve/static_dc.parquet"))
# get winners and losers
## import in fitness
static_fitness.df <- read.csv(here("data/ci_static.csv"))
## get winner situation
static_fitness.df2 <- static_fitness.df %>% 
  filter(id_1 != id_2) %>% 
  mutate(winning_id = case_when(
    fitness_difference > 0 ~ id_1,
    fitness_difference< 0 ~ id_2
  ),
  losing_id = case_when(
    fitness_difference < 0 ~ id_1,
    fitness_difference> 0 ~ id_2
  ))

# left join
static_dc.df2 <- static_dc.df %>% 
  left_join(select(static_fitness.df2, id_1, id_2, winning_id, losing_id, fitness_difference), by = c("id_1", "id_2"))

# get winner-loser difference in terms of I+Ig also filter out to onyl very strong fitness difference
static_dc.df3 <- static_dc.df2 %>% 
  mutate(total_diff = case_when(
    fitness_difference > 0 ~ total1-total2,
    fitness_difference< 0 ~ total2-total2
  ),
  total_winner = case_when(
    fitness_difference > 0 ~ total1,
    fitness_difference< 0 ~ total2
  ),
  total_loser = case_when(
    fitness_difference > 0 ~ total2,
    fitness_difference< 0 ~ total1
  )) %>% 
  filter(abs(fitness_difference) > 0.5)

plot

static_dc.pl <- ggplot() +
  geom_path(data = static_dc.df3, aes(x= total_winner, y = R, group = id_alt, color = "Winner"), alpha = 0.5, arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  geom_path(data = static_dc.df3, aes(x= total_loser, y = R, group = id_alt, color = "Loser"),
          alpha = 0.5,arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  labs(color = "Status", x = "Asexual & sexual iRBC", y = "RBC") +
  scale_color_manual(values=c("Winner" = "#4575b4","Loser"= "#fc8d59"))  +
  theme_bw() + 
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE, accuracy = 0.1))

#———co-infection invasion —————# # get invasion dynamic

# get invasion df
invasion_fitness.df <- read.csv(here("data/ci_invasion.csv"))

# get cue range
ci_cue_range <- read.csv(here("data/cue_range_ci.csv"))
invasion_fitness.df2 <- invasion_fitness.df %>% 
  left_join(select(ci_cue_range, id, mut_cue = cue, mut_low = low, mut_high = high, mut_by = by), by = c("mut_id"= "id")) %>% 
  left_join(select(ci_cue_range, id, res_cue = cue, res_low = low, res_high = high, res_by = by), by = c("res_id"= "id"))

function to get dynamic

get_invasion_dyn <- function(df){
  # get cues
  mut_cue <- df$mut_cue
  res_cue <- df$res_cue
  
  # get info of cues (for co infection)
  if(stringr::str_detect(mut_cue, "-i")){mut_cue = gsub("*-i", "1", mut_cue)}
  if(stringr::str_detect(mut_cue, "-i", negate = T)){mut_cue = mut_cue}
  if(stringr::str_detect(res_cue, "-i")){res_cue = gsub("*-i", "2", res_cue)}
  if(stringr::str_detect(res_cue, "-i", negate = T)){res_cue = res_cue}
  
  # get log
  mut_log <- ifelse(stringr::str_detect(df$mut_id, "log"), "log10", "none")
  res_log <- ifelse(stringr::str_detect(df$res_id, "log"), "log10", "none")
  
  # get parameters
  mut_par <- c(df$mut_var1_opt, df$mut_var2_opt, df$mut_var3_opt, df$mut_var4_opt)
  res_par <- c(df$res_var1, df$res_var2, df$res_var3, df$res_var4)
  
  # get cue range
  mut_cue_range <- seq(df$mut_low, df$mut_high, by = df$mut_by)
  res_cue_range <- seq(df$res_low, df$res_high, by = df$res_by)
  
  # get dynamics of co infection
  ci_dyn <- chabaudi_ci_clean(
    parameters_cr_1 = mut_par,
    parameters_cr_2 = res_par,
                  immunity = "tsukushi",
                  parameters = parameters_tsukushi,
                  cue_1 = mut_cue,
                  cue_2 = res_cue,
                  cue_range_1 = mut_cue_range,
                 cue_range_2 = res_cue_range,
                log_cue_1 = mut_log,
                log_cue_2 = res_log,
                solver = "vode",
                time_range = seq(0, 30, 0.001),
    dyn = T)
  
  # append label to all df
 ci_dyn2 <- cbind(ci_dyn, mut_id = df$mut_id, res_id = df$res_id)
  
  # write
 write_parquet(ci_dyn2, paste0(here("data/ci_invasion_dyn/"), df$mut_id, "-", df$res_id, ".parquet"))
}

run dynamic funciton

# get function and parameters
source(here("functions/chabaudi_ci_clean.R"))
parameters_tsukushi <- c(R1 = 8.89*(10^6), # slightly higher
                lambda = 3.7*(10^5),
                mu = 0.025, 
                p = 8*(10^-6), # doubled form original
                alpha = 1, 
                alphag = 2, 
                beta = 5.721, 
                mum = 48, 
                mug = 4, 
                I0 = 43.85965, 
                Ig0 = 0, 
                a = 150, 
                b = 100, 
                sp = 1,
                psin = 16.69234,
                psiw = 0.8431785,
                phin = 0.03520591, 
                phiw = 550.842,
                iota = 2.18*(10^6),
                rho = 0.2627156)
# split
invasion.ls <- split(invasion_fitness.df2, seq(nrow(invasion_fitness.df2)))

# run function
mclapply(invasion.ls, get_invasion_dyn, mc.cores = 4)

process data

# import in invasion dynamics
invasion_dyn.ls <- list.files(path = here("data/ci_invasion_dyn"), pattern = "*.parquet", full.names = T)
invasion_dyn.ls <- lapply(invasion_dyn.ls, read_parquet)

# filter and so on
invasion_dyn.ls2 <- mclapply(invasion_dyn.ls[167:177], mc.cores = 4, function(x){
  x2 <- x %>% 
    filter(variable == "I1" | variable == "Ig1" | variable == "I2" | variable == "Ig2" | variable == "R") %>% 
    mutate(id_alt = paste(mut_id, res_id)) %>% 
    select(id_alt, time, variable, value) %>% 
    tidyr::pivot_wider(names_from = variable, values_from = value, id_cols = c(time, id_alt)) %>%
  mutate(total1 = I1+Ig1, total2 = I2+Ig2)
  
  write_parquet(x2, paste0(here("data/disease_curve/ci_invasion/"), unique(x2$id_alt), "_dc.parquet"))
})

# fetch data
invasion_dyn.ls2 <- list.files(path = here("data/disease_curve/ci_invasion"), pattern = "*.parquet", full.names = T)
invasion_dyn.ls2 <- lapply(invasion_dyn.ls2, read_parquet)
invasion_dc.df <- do.call(rbind, invasion_dyn.ls2)
invasion_dc.df <- invasion_dc.df %>% 
  mutate(mut_id = gsub(" .*", "", id_alt),
         res_id = gsub(".* ", "", id_alt)) %>% 
  filter(mut_id != res_id)
#write_parquet(invasion_dc.df, here("data/disease_curve/invasion_dc.parquet"))

further processing

invasion_dc.df <- read_parquet(here("data/disease_curve/invasion_dc.parquet"))
# get winners and losers
invasion_fitness.df <- read.csv(here("data/ci_invasion.csv"))
invasion_dc.df2 <- invasion_dc.df %>% 
  left_join(invasion_fitness.df, by = c("mut_id", "res_id")) %>% 
  mutate(
  total_winner = case_when(
    fitness> 0 ~ total1,
    fitness< 0 ~ total2
  ),
  total_loser = case_when(
    fitness > 0 ~ total2,
    fitness < 0 ~ total1
  )) %>% 
  filter(abs(fitness) > 0.5)

plot

invasion_dc.pl <- ggplot() +
  geom_path(data = invasion_dc.df2, aes(x= total_winner, y = R, group = id_alt, color = "Winner"), alpha = 0.5, arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  geom_path(data = invasion_dc.df2, aes(x= total_loser, y = R, group = id_alt, color = "Loser"),
          alpha = 0.5,arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
  labs(color = "Status", x = "Asexual & sexual iRBC", y = "RBC") +
  scale_color_manual(values=c("Winner" = "#4575b4","Loser"= "#fc8d59"))  +
  theme_bw() + 
  scale_y_continuous(labels = function(x) format(x, scientific = TRUE, accuracy = 0.1)) %>% 
  theme(legend.position = "none")

#——— quantifying disease curve area ————# # function to calculate area between sets of points -> from https://stackoverflow.com/questions/3672260/area-covered-by-a-point-cloud-with-r

library(splancs)
Loading required package: sp

Spatial Point Pattern Analysis Code in S-Plus
 
 Version 2 - Spatial and Space-Time analysis


Attaching package: ‘splancs’

The following object is masked from ‘package:dplyr’:

    tribble
cha<-function(df){
  x <- df$total
  y <- df$R
chull(x,y)->i
return(areapl(cbind(x[i],y[i])))
}
library(splancs)
cha<-function(df){
  x <- df$total
  y <- df$R
chull(x,y)->i
return(areapl(cbind(x[i],y[i])))
}

loop to get area: single infection

# join with fitness
si_fitness.df <- si_fitness.df %>% left_join(ez_label, by = c("id" = "id_si"))
Error in is.data.frame(y) : object 'ez_label' not found

coinfection

# split
ci_dc_high.ls <- split(ci_dc.high2, ci_dc.high2$ez_label)
ci_dc_poor.ls <- split(ci_dc.poor, ci_dc.poor$label)

# run function to find area
ci_dc_high.area <- cbind.data.frame(area = as.numeric(lapply(ci_dc_high.ls, cha)), id_alt = names(lapply(ci_dc_high.ls, cha)), value = unique(ci_dc.high2$value))

ci_dc_poor.area <- cbind.data.frame(area = as.numeric(lapply(ci_dc_poor.ls, cha)), id_alt = names(lapply(ci_dc_poor.ls, cha)), value = unique(ci_dc.poor$value))

# edit and join
ci_dc_high.area2 <-  ci_dc_high.area %>% 
  select(area, value) %>% 
  mutate(condition = "Co-infection")

ci_dc_poor.area2 <-  ci_dc_poor.area %>% 
  select(area, value) %>% 
  mutate(condition = "Co-infection")

dual cue

# split
dual.dc <- read_parquet(here("data/disease_curve/dual_dc.parquet"))
dual_dc.ls <- split(dual.dc, dual.dc$label_alt)

# get area
dual_dc.area <- cbind.data.frame(area = as.numeric(lapply(dual_dc.ls, cha)), id_alt = names(lapply(dual_dc.ls, cha)))

# bind with fitness
dual_fitness.df <- dual_fitness.df %>% mutate(id_alt = paste(label, "+", label_b))
dual_dc.area2 <- dual_dc.area %>% 
  left_join(dual_fitness.df, by = "id_alt") %>% 
  select(area, value) %>% 
  mutate(condition = "Dual-cue") %>% 
  filter(value > 2)
dual_dc.area2

#—— get fitted scatter plot for all single infection, co infection, and dual cue ——–#

# plot
library("ggpmisc")
Loading required package: ggpp

Attaching package: ‘ggpp’

The following object is masked from ‘package:ggplot2’:

    annotate

#——- plot together with disease curve ——–#

# single infection
si_vir.pl <- ggarrange(si_dc.pl, si_area.pl, align = "h", widths = c(1, 0.35))
Warning: Graphs cannot be horizontally aligned unless the axis parameter is set. Placing graphs unaligned.
# single infection
si_vir.pl <- ggarrange(si_dc.pl, si_area.pl, align = "h", widths = c(1, 0.35))
Warning: Graphs cannot be horizontally aligned unless the axis parameter is set. Placing graphs unaligned.
# co-infection
ci_vir.pl <- ggarrange(ci_dc.pl, ci_area.pl, align = "h", widths = c(1, 0.35))
Warning: Graphs cannot be horizontally aligned unless the axis parameter is set. Placing graphs unaligned.

#——— static area comparison ————-# # compute area

# import in dc dynamic and fitness
static_dc.df <- read_parquet(here("data/disease_curve/static_dc.parquet"))
static_fitness.df <- read.csv(here("data/ci_static.csv"))

# get winner and loser
static_dc.df4 <- static_dc.df %>% 
  left_join(select(static_fitness.df, id_1, id_2, fitness_difference), by = c("id_1", "id_2")) %>%
  filter(id_1 != id_2) %>% 
  mutate(
  total_winner = case_when(
    fitness_difference > 0 ~ total1,
    fitness_difference< 0 ~ total2
  ),
  total_loser = case_when(
    fitness_difference > 0 ~ total2,
    fitness_difference< 0 ~ total1
  ))%>% 
  filter(abs(fitness_difference) > 0.5)

# split by winner and loser
static_dc.ls1 <- split(select(static_dc.df4, R, total = total_winner), static_dc.df4$id_alt)
static_dc.ls2 <- split(select(static_dc.df4, R, total = total_loser), static_dc.df4$id_alt)

# get area
static_win.area <- cbind.data.frame(area = as.numeric(lapply(static_dc.ls1, cha)), status = "Winner")
static_loser.area <- cbind.data.frame(area = as.numeric(lapply(static_dc.ls2, cha)), status = "Loser")

# pair
static.area <- cbind(select(static_win.area, Winner = area),
                     select(static_loser.area, Loser = area)) %>% 
  mutate(classification = ifelse(Winner>Loser, "Winner larger area", "Loser larger area"))

plot static

#——— invasion area comparison —————–# # get area

# import in dc dynamic and fitness
invasion_dc.df <- read_parquet(here("data/disease_curve/invasion_dc.parquet"))
invasion_fitness.df <- read.csv(here("data/ci_invasion.csv"))

invasion_dc.df4 <- invasion_dc.df %>% 
  left_join(invasion_fitness.df, by = c("mut_id", "res_id")) %>% 
  mutate(
  total_winner = case_when(
    fitness> 0 ~ total1,
    fitness< 0 ~ total2
  ),
  total_loser = case_when(
    fitness > 0 ~ total2,
    fitness < 0 ~ total1
  )) %>% 
  filter(abs(fitness) > 0.5)

# split by winner and loser
invasion_dc.ls1 <- split(select(invasion_dc.df4, R, total = total_winner), invasion_dc.df4$id_alt)
invasion_dc.ls2 <- split(select(invasion_dc.df4, R, total = total_loser), invasion_dc.df4$id_alt)

# get area
invasion_win.area <- cbind.data.frame(area = as.numeric(lapply(invasion_dc.ls1, cha)), status = "Winner")
invasion_loser.area <- cbind.data.frame(area = as.numeric(lapply(invasion_dc.ls2, cha)), status = "Loser")

# pair
invasion.area <- cbind(select(invasion_win.area, Winner = area),
                     select(invasion_loser.area, Loser = area)) %>% 
  mutate(classification = ifelse(Winner>Loser, "Winner larger area", "Loser larger area"))

plot

#—— plot together ————-#

# pairwise comparison for static and invasive comeptition
heterocue_comp.pl <- ggarrange(static_area.pl, invasion_area.pl, ncol = 2, nrow = 1, align = "v")

# join inthe other disease curves
ggarrange(si_vir.pl, ci_vir.pl, dual_vir.pl, heterocue_comp.pl, ncol = 2, nrow = 2, labels = c("A", "B", "C", "D"), heights = c(1, 0.8))

ggsave(here("figures/plos-bio/virulence.tiff"), units = "px", width = 2250, height = 1600, scale = 1.9, dpi=300, bg = "white")

#====================================# # dual cue dynamics figure #===================================#

get dual dynamics

dual.dyn <- chabaudi_si_clean(
  parameters_cr = c(4.446192033,    10.97518275,    1.38762817, 23.3059254, -3.452052371,   -18.0070692,    39.66614226,    -3.545193141,   18.78350799),
  immunity = "tsukushi",
  parameters = parameters_tsukushi,
  time_range = seq(0, 30, by = 1e-3),
  cue_range =  seq(6, 7, by = 1/500),
  cue_range_b = seq(0, log10(6*(10^6)), by = (log10(6*(10^6)))/500),
  cue = "R",
  cue_b = "I",
  log_cue = "log10",
  log_cue_b = "log10",
  solver = "vode",
  dyn = T
)

# filter out relevent dataframes
dual.dyn_f <- dual.dyn %>% 
  filter(variable %in% c("I", "Ig", "G", "R", "N", "W"))

# cr only
dual.dyn_cr <- dual.dyn %>% filter(variable == "cr")

plot

dual_I.plt <- ggplot() +
  geom_line(data = dual.dyn_f %>% filter(variable == "I"), aes(x = time, y = value/(10^5)),
            color = "#4575b4") +
  geom_point(data = dual.dyn_f %>% filter(variable == "I" & row_number() %% 1000 == 0), 
             aes(x = time, y = value/(10^5)), size = 2, color = "#4575b4") +
  geom_line(data = dual.dyn_cr, aes(x = time, y = value)) +
  scale_y_continuous(name = "Conversion rate",
                     sec.axis = sec_axis(~.*10^5, name="Asexual iRBC per µL")) +
  labs(x = "Time (days)") +
  xlim(0, 20) +
  theme_bw() +
  theme(legend.position = "none")

dual_Ig.plt <-ggplot() +
  geom_line(data = dual.dyn_f %>% filter(variable == "Ig"), aes(x = time, y = value/(10^5)),
            color = "#4575b4") +
  geom_point(data = dual.dyn_f %>% filter(variable == "Ig" & row_number() %% 1000 == 0), 
             aes(x = time, y = value/(10^5)), size = 2, color = "#4575b4") +
  geom_line(data = dual.dyn_cr, aes(x = time, y = value)) +
  scale_y_continuous(name = "Conversion rate",
                     sec.axis = sec_axis(~.*10^5, name="Sexual iRBC per µL")) +
  labs(x = "Time (days)") +
  xlim(0, 20) +
  theme_bw() +
  theme(legend.position = "none")

dual_G.plt <-ggplot() +
  geom_line(data = dual.dyn_f %>% filter(variable == "G"), aes(x = time, y = value/(10^4)),
            color = "#4575b4") +
  geom_point(data = dual.dyn_f %>% filter(variable == "G" & row_number() %% 1000 == 0), 
             aes(x = time, y = value/(10^4)), size = 2, color = "#4575b4") +
  geom_line(data = dual.dyn_cr, aes(x = time, y = value)) +
  scale_y_continuous(name = "Conversion rate",
                     sec.axis = sec_axis(~.*10^4, name="Gametocyte per µL")) +
  labs(x = "Time (days)") +
  xlim(0, 20) +
  theme_bw() +
  theme(legend.position = "none")

dual_R.plt <-ggplot() +
  geom_line(data = dual.dyn_f %>% filter(variable == "R"), aes(x = time, y = value/(10^7)),
            color = "#4575b4") +
  geom_point(data = dual.dyn_f %>% filter(variable == "R" & row_number() %% 1000 == 0), 
             aes(x = time, y = value/(10^7)), size = 2, color = "#4575b4") +
  geom_line(data = dual.dyn_cr, aes(x = time, y = value)) +
  scale_y_continuous(name = "Conversion rate",
                     sec.axis = sec_axis(~.*10^7, name="RBC per µL")) +
  labs(x = "Time (days)") +
  xlim(0, 20) +
  theme_bw() +
  theme(legend.position = "none")

dual_N.plt <-ggplot() +
  geom_line(data = dual.dyn_f %>% filter(variable == "N"), aes(x = time, y = value*10),
            color = "#4575b4") +
  geom_point(data = dual.dyn_f %>% filter(variable == "N" & row_number() %% 1000 == 0), 
             aes(x = time, y = value*10), size = 2, color = "#4575b4") +
  geom_line(data = dual.dyn_cr, aes(x = time, y = value)) +
  scale_y_continuous(name = "Conversion rate",
                     sec.axis = sec_axis(~.*0.1, name="Indiscriminate immunity")) +
  labs(x = "Time (days)") +
  xlim(0, 20) +
  theme_bw() +
  theme(legend.position = "none")

dual_W.plt <-ggplot() +
  geom_line(data = dual.dyn_f %>% filter(variable == "W"), aes(x = time, y = value*2),
            color = "#4575b4") +
  geom_point(data = dual.dyn_f %>% filter(variable == "W" & row_number() %% 1000 == 0), 
             aes(x = time, y = value*2), size = 2, color = "#4575b4") +
  geom_line(data = dual.dyn_cr, aes(x = time, y = value)) +
  scale_y_continuous(name = "Conversion rate",
                     sec.axis = sec_axis(~.*0.5, name="Targeted immunity")) +
  labs(x = "Time (days)") +
  xlim(0, 20) +
  theme_bw() +
  theme(legend.position = "none")

plot together

ggarrange(dual_I.plt, dual_Ig.plt, dual_G.plt, dual_R.plt, dual_N.plt, dual_W.plt, nrow = 3, ncol = 2, align = "hv", labels = c("A", "B", "C", "D", "E", "F"))
ggsave(here("figures/plos-bio/dual_dyn.tiff"), units = "px", width = 2250, height = 2000, scale = 1, dpi=300, bg = "white")

#======================================# # Single and co-infection verification #======================================# # single infection

# import in all single infection data
si_val.ls <- list.files(path = here("data/si_validation"), pattern = "*.csv", full.names = T)

si_val.df <- lapply(si_val.ls, read.csv)
si_val.df <- do.call(rbind, si_val.df)

# get max fitness from simulation. left join with si_opt
si_opt.df <- read.csv(here("data/si_opt.csv"))

# we can see that all of the randomly simulated models have a fitness value that is less than the optimized model
si_val.df2 <- select(si_val.df, V1, id) %>%
  left_join(si_opt.df, by =c("id" = "id")) %>% 
  mutate(fitness_difference = fitness_20 - V1) %>% 
  left_join(select(ez_label, id_si, ez_label_si), by = c("id" = "id_si"))

Model validation

plot

si_val.plt <- ggplot(data = si_val.df2, aes(x = fitness_difference)) +
  geom_histogram(bins = 50) +
  geom_vline(xintercept = 0, color = "#fc8d59") +
  facet_wrap(~ez_label_si, scales = "free", ncol = 3) +
  labs(x = "Optimized fitness - random fitness", y = "Frequency") +
  theme_bw()

ci_val.plt <- ggplot(data = ci_val.df2, aes(x = V1)) +
  geom_histogram(bins = 50) +
  geom_vline(xintercept = 0, color = "#fc8d59") +
  facet_wrap(~ez_label, scales = "free", ncol = 4) +
  labs(x = "Fitness difference between\noptimized and random strain", y = "Frequency") +
  theme_bw()

ggarrange(si_val.plt, ci_val.plt, align = "hv", labels = c("A", "B"), widths = c(3,4))
ggsave(here("figures/plos-bio/validation.tiff"), units = "px", width = 2250, height = 1300, scale = 1.6, dpi=300, bg = "white")

#=========================# # Monte carlo dynamics supplementary #=========================# # run code in report 16

mc_dyn_a <- ggplot() +
  geom_line(data = reference.df, aes(x = time, y = cr)) +
  geom_ribbon(data = diff.df, aes(x = time, ymin = cr_bot, ymax = cr_top), alpha = 0.5, fill = "#fc8d59") +
  facet_wrap(~cue, ncol = 2) +
  labs(x = "Time (days)", y = "Conversion rate") +
  theme_bw()
  
# plot fitness timeseries. When if tiness lost? At the latter part
mc_dyn_b  <- ggplot() +
  geom_line(data = reference.df, aes(x = time, y = tau)) +
  geom_ribbon(data = diff.df, aes(x = time, ymin = tau_bot, ymax = tau_top), alpha = 0.5, fill = "#fc8d59") +
  facet_wrap(~cue, ncol = 2) +
  labs(x = "Time (days)", y = "Transmission potential") +
  theme_bw()

ggarrange(mc_dyn_a, mc_dyn_b, ncol = 1, align = "v", labels = c("A", "B"))
Warning: Removed 1 row containing missing values (`geom_line()`).
ggsave(here("figures/plos-bio/MC_dyn.tiff"), units = "px", width = 2250, height = 2000, scale = 1.3, dpi=300, bg = "white")

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQpgYGB7cn0KbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGZvcmNhdHMpCmxpYnJhcnkoaGVyZSkKbGlicmFyeShkZVNvbHZlKQpsaWJyYXJ5KGNyb25lKQpsaWJyYXJ5KG9wdGltUGFyYWxsZWwpCmxpYnJhcnkoZG9QYXJhbGxlbCkKbGlicmFyeShkb1JORykKbGlicmFyeShhcnJvdykKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KHBhcmFsbGVsKQpsaWJyYXJ5KGdncHVicikKYGBgCgpOb3RlYm9vayBmb3IgcGxvdHRpbmcgYWxsIG9mIHRoZSBmaWd1cmVzIGZvciBQbG9TIEJpb2xvZ3kgbWFudXNjcmlwdCBzdWJtaXNzaW9uCgpHdWlkZWxpbmVzOiB0YWtlbiBmcm9tIGh0dHBzOi8vam91cm5hbHMucGxvcy5vcmcvcGxvc2Jpb2xvZ3kvcy9maWd1cmVzI2xvYy1maWd1cmUtZmlsZS1yZXF1aXJlbWVudHMKMS4gZm9ybWF0OiBlcHMKMi4gbWF4IGZpbGUgc2l6ZTogMTAgTUIKMy4gdGV4dCBzaXplOiBBcmlhbCwgVGltZXMsIG9yIFN5bWJvbCBmb250IG9ubHkgaW4gOC0xMiBwb2ludAoyLiBmaWd1cmUgc2l6ZTogV2lkdGg6IDc4OSDigJMgMjI1MCBwaXhlbHMgKGF0IDMwMCBkcGkpLiBIZWlnaHQgbWF4aW11bTogMjYyNSBwaXhlbHMgKGF0IDMwMCBkcGkpLgoKCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKZmlndXJlIDE6IGJlc3Qgc2luZ2xlIGFuZCBjby1pbmZlY3Rpb24gY3VlCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKRmlndXJlIGRpc3BsYXlpbmcgdGhlIHJlYWN0aW9uIG5vcm1zIG9mIGJlc3Qgc2luZ2xlIGFuZCBjby1pbmZlY3Rpb24uCgojLS0tLS0tLSBvcHRpbWFsIGN1ZSByZWFjdGlvbiBub3JtIC0tLS0tLS0tLS0tIwojIHJlYWQgZGF0YQpgYGB7cn0KIyBzaW5nbGUgaW5mZWN0aW9uIGR5bmFtaWNzLCByZWFjdGlvbiBub3JtcywgYW5kIHJ1Z3MKc2lfZHluLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL3NpX2R5bi9zaV9keW5fMzAucGFycXVldCIpKSAKc2lfcm4uZGYgPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvc2lfZHluL3NpX3JuLnBhcnF1ZXQiKSkKc2lfcnVnLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL3NpX2R5bi9zaV9ydWcucGFycXVldCIpKSAlPiUgCiAgZGlzdGluY3QodmFsdWUsIGxhYmVsLCAua2VlcF9hbGwgPSBUKQoKIyBjby1pbmZlY3Rpb24gZHluYW1pY3MsIHJlYWN0aW9uIG5vcm1zLCBhbmQgcnVncwpjaV9keW4uZGYgPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvY2lfZHluL2NpX2R5bi5wYXJxdWV0IikpCmNpX3JuLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2NpX2R5bi9jaV9ybi5wYXJxdWV0IikpCmNpX3J1Zy5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9jaV9keW4vY2lfcnVnLnBhcnF1ZXQiKSkgJT4lIAogIGRpc3RpbmN0KHZhbHVlLCBsYWJlbCwgLmtlZXBfYWxsID0gVCkKYGBgCgojIHByb2Nlc3MgZGF0YSBmb3IgcmVhY3Rpb24gbm9ybQpgYGB7cn0KIyBpbXBvcnQgbGFiZWxsaW5nIHNjaGVtZQplel9sYWJlbCA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2V6X2xhYmVsLmNzdiIpKQoKIyBnZXQgc2lfbGFiZWwgd2l0aCBjaSBjdWUgcmFuZ2UKc2lfY2lfcnVnLmRmIDwtIGNpX3J1Zy5kZiAlPiUgCiAgbXV0YXRlKGxhYmVsX3NpID0gY2FzZV93aGVuKAogICAgbGFiZWwgJWluJSBjKCJJIiwgIkkxK0kyIikgfiAiSSIsCiAgICBsYWJlbCAlaW4lIGMoIkkgbG9nIiwiSTErSTIgbG9nIikgfiAiSSBsb2ciLAogICAgbGFiZWwgJWluJSBjKCJJZyIsICJJZzErSWcyIikgfiAiSWciLAogICAgbGFiZWwgJWluJSBjKCJJZyBsb2ciKSB+ICJJZyBsb2ciLAogICAgbGFiZWwgJWluJSBjKCJzdW0iLCAiSStJZyIpIH4gIkkrSWciLAogICAgbGFiZWwgJWluJSBjKCJzdW0gbG9nIiwgIkkrSWcgbG9nIikgfiAiSStJZyBsb2ciLAogICAgbGFiZWwgPT0gIlIiIH4gIlIiLAogICAgbGFiZWwgPT0gIlIgbG9nIiB+ICJSIGxvZyIsCiAgICBsYWJlbCAlaW4lIGMoIkciLCAiRzErRzIiKSB+ICJHIiwKICAgIGxhYmVsID09ICJHIGxvZyIgfiAiRyBsb2ciCiAgKSkgCgojIGdldCBsaW1pdCBmb3Igc2lfcnVnCnNpX3J1Z19saW0uZGYgPC0gc2lfcnVnLmRmICU+JSAKICBmaWx0ZXIodGltZSA8PSAyMCkgJT4lCiAgZ3JvdXBfYnkobGFiZWwpJT4lIAogIHN1bW1hcmlzZShtaW4gPSBtaW4odmFsdWUsIG5hLnJtID0gVCkqMC45LAogICAgICAgICBtYXggPSBtYXgodmFsdWUsIG5hLnJtID0gVCkqMS4xKSAlPiUgCiAgc2VsZWN0KGxhYmVsX3NpID0gbGFiZWwsIG1pbl9zaSA9IG1pbiwgbWF4X3NpID0gbWF4KQoKIyBmaWx0ZXIgdG8gcmVzdHJpY3Rpb24gY29udmVyc2lvbiByYXRlIHJlYWN0aW9uIG5vcm0gcmFuZ2UgdG8gY3VlIHJhbmdlcyB0aGF0IGFwcGVhciBpbiBydWcKIyMgY2hhbmdlIHRvIEluZi8taW5mIHRvIE5BLiBOb3RlIHRoYXQgSSBhbSBmaXJzdCBqb2luaW5nIHdpdGggc2kgcnVnIGxpbSB0byBjaGVjayB3aGljaCBsaW1pdCBpcyBsYXJnZXIsIFdlIHdpbGwgZ28gd2l0aCB0aGUgY3VlIHJhbmdlIHRoYXQgaGFzIHRoZSBsYXJnZXN0IHNwYW4KY2lfcnVnX2xpbS5kZiA8LSBzaV9jaV9ydWcuZGYgJT4lIAogIGdyb3VwX2J5KGxhYmVsKSAlPiUgCiAgbXV0YXRlKG1pbiA9IG1pbih2YWx1ZSwgbmEucm0gPSBUKSowLjksCiAgICAgICAgIG1heCA9IG1heCh2YWx1ZSwgbmEucm0gPSBUKSoxLjEpICU+JSAKICBkaXN0aW5jdChsYWJlbCwgLmtlZXBfYWxsID0gVCkgJT4lIAogIHNlbGVjdChsYWJlbCwgbGFiZWxfc2ksIG1pbiwgbWF4KQoKcnVnX2xpbS5maW5hbCA8LSBjaV9ydWdfbGltLmRmICU+JSBsZWZ0X2pvaW4oc2lfcnVnX2xpbS5kZiwgYnkgPSAibGFiZWxfc2kiKSAlPiUgCiAgbXV0YXRlKGZpbmFsX21pbiA9IG1pbihtaW4sIG1pbl9zaSksCiAgICAgICAgIGZpbmFsX21heCA9IG1heChtYXgsIG1heF9zaSkpCgojIGdldCBzZWNvbmQgcnVnX2xpbS5maW5hbCBmb3Igc2luZ2xlIGluZmVjdGlvbgpydWdfbGltLmZpbmFsMiA8LSBydWdfbGltLmZpbmFsICU+JSAKICBncm91cF9ieShsYWJlbF9zaSkgJT4lIAogIG11dGF0ZShmaW5hbF9taW4gPSBtaW4oZmluYWxfbWluLCBuYS5ybSA9IFQpLAogICAgICAgICBmaW5hbF9tYXggPSBtYXgoZmluYWxfbWF4LCBuYS5ybSA9IFQpKQoKIyBmaWx0ZXIgY2lfcm4gYnkgbGltaXQKY2lfcm4uZGYyIDwtIGNpX3JuLmRmICU+JSAKICBsZWZ0X2pvaW4ocnVnX2xpbS5maW5hbCwgYnkgID0gImxhYmVsIikgJT4lIAogIGdyb3VwX2J5KGxhYmVsKSAlPiUgCiAgZmlsdGVyKGN1ZV9yYW5nZSA8PSBmaW5hbF9tYXggJiBjdWVfcmFuZ2UgPj0gZmluYWxfbWluKSAlPiUgCiAgYXJyYW5nZShjdWVfcmFuZ2UsIC5ieV9ncm91cCA9IFQpICU+JSAKICBmaWx0ZXIocm93X251bWJlcigpICUlIDEwID09IDApIApgYGAKCiMgbWF0Y2ggc2luZ2xlIGluZmVjdGlvbiBybiB3aXRoIGNvaW5mZWN0aW9uIApgYGB7cn0KIyBnZXQgY2kgbGFiZWwgdG8gc2kgcnVnIGFuZCBmaWx0ZXIgYnkgbGltaXQKc2lfcm4uZGYyIDwtIGxlZnRfam9pbihzaV9ybi5kZiwgc2VsZWN0KGV6X2xhYmVsLCBsYWJlbF9zaSwgbGFiZWxfY2kpLCBieSA9IGMoImxhYmVsIiA9ICJsYWJlbF9zaSIpKSAlPiUgCiAgbGVmdF9qb2luKHJ1Z19saW0uZmluYWwsIGJ5ICA9IGMoImxhYmVsX2NpIiA9ICJsYWJlbCIpKSAlPiUgCiAgZ3JvdXBfYnkobGFiZWxfY2kpICU+JSAKICBmaWx0ZXIoY3VlX3JhbmdlIDw9IGZpbmFsX21heCAmIGN1ZV9yYW5nZSA+PSBmaW5hbF9taW4pICU+JSAKICBhcnJhbmdlKGN1ZV9yYW5nZSwgLmJ5X2dyb3VwID0gVCkgJT4lIAogIGZpbHRlcihyb3dfbnVtYmVyKCkgJSUgMTAgPT0gMCkgJT4lIAogIHNlbGVjdChjdWVfcmFuZ2UsIGNyLCBsYWJlbF9jaSwgbGFiZWxfc2kpCgojIGdldCBjaSBsYWJlbCB0byBzaSBydWcsIHdlIHdpbGwga2VlcCBvbmUgdW5pcXVlIHZhbHVlIHBlciBsYWJlbApzaV9ydWcuZGYyIDwtIHNlbGVjdChzaV9ydWcuZGYsIHZhbHVlLCBsYWJlbF9zaSA9IGxhYmVsKSAlPiUgZGlzdGluY3QodmFsdWUsIGxhYmVsX3NpKQpgYGAKCiMgcGxvdCByZWFjdGlvbiBub3JtCmBgYHtyfQojIGpvaW4gd2l0aCBlemxhYmVsCmNpX3JuLmRmMyA8LSBjaV9ybi5kZjIgJT4lIGxlZnRfam9pbihlel9sYWJlbCwgYnkgPSBjKCJsYWJlbCIgPSAibGFiZWxfY2kiKSkKc2lfcm4uZGYzIDwtIHNpX3JuLmRmMiAlPiUgbGVmdF9qb2luKGV6X2xhYmVsLCBieSA9ICJsYWJlbF9jaSIpCmNpX3J1Zy5kZjMgPC0gY2lfcnVnLmRmICU+JSBsZWZ0X2pvaW4oZXpfbGFiZWwsIGJ5ID0gYygibGFiZWwiID0gImxhYmVsX2NpIikpCnNpX3J1Zy5kZjMgPC0gc2lfcnVnLmRmMiAlPiUgbGVmdF9qb2luKGV6X2xhYmVsLCBieSA9ICJsYWJlbF9zaSIpCmBgYAoKCmBgYHtyfQojIHJlZG8gb3JkZXIgb2YgY3VlcwpjaV9ybi5kZjMkZXpfbGFiZWwgPC0gZmFjdG9yKGNpX3JuLmRmMyRlel9sYWJlbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkFzZXh1YWwgaVJCQyIsICJBc2V4dWFsIGlSQkMgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUb3RhbCBhc2V4dWFsIGlSQkMiLCAiVG90YWwgYXNleHVhbFxuaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNleHVhbCBpUkJDIiwgIlNleHVhbCBpUkJDIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQXNleHVhbCZzZXh1YWwgaVJCQyIsICJBc2V4dWFsJnNleHVhbFxuaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvdGFsIGlSQkMiLCAiVG90YWwgaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdhbWV0b2N5dGUiLCAiR2FtZXRvY3l0ZSBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvdGFsIGdhbWV0b2N5dGUiLCAiVG90YWwgc2V4dWFsIGlSQkMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSQkMiLCAiUkJDIGxvZzEwIikpIAoKc2lfcm4uZGYzJGV6X2xhYmVsIDwtIGZhY3RvcihzaV9ybi5kZjMkZXpfbGFiZWwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJBc2V4dWFsIGlSQkMiLCAiQXNleHVhbCBpUkJDIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVG90YWwgYXNleHVhbCBpUkJDIiwgIlRvdGFsIGFzZXh1YWxcbmlSQkMgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTZXh1YWwgaVJCQyIsICJTZXh1YWwgaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFzZXh1YWwmc2V4dWFsIGlSQkMiLCAiQXNleHVhbCZzZXh1YWxcbmlSQkMgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUb3RhbCBpUkJDIiwgIlRvdGFsIGlSQkMgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHYW1ldG9jeXRlIiwgIkdhbWV0b2N5dGUgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUb3RhbCBnYW1ldG9jeXRlIiwgIlRvdGFsIHNleHVhbCBpUkJDIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUkJDIiwgIlJCQyBsb2cxMCIpKQoKY2lfcnVnLmRmMyRlel9sYWJlbCA8LSBmYWN0b3IoY2lfcnVnLmRmMyRlel9sYWJlbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkFzZXh1YWwgaVJCQyIsICJBc2V4dWFsIGlSQkMgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUb3RhbCBhc2V4dWFsIGlSQkMiLCAiVG90YWwgYXNleHVhbFxuaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNleHVhbCBpUkJDIiwgIlNleHVhbCBpUkJDIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQXNleHVhbCZzZXh1YWwgaVJCQyIsICJBc2V4dWFsJnNleHVhbFxuaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvdGFsIGlSQkMiLCAiVG90YWwgaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdhbWV0b2N5dGUiLCAiR2FtZXRvY3l0ZSBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvdGFsIGdhbWV0b2N5dGUiLCAiVG90YWwgc2V4dWFsIGlSQkMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSQkMiLCAiUkJDIGxvZzEwIikpCgpzaV9ydWcuZGYzJGV6X2xhYmVsIDwtIGZhY3RvcihzaV9ydWcuZGYzJGV6X2xhYmVsLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiQXNleHVhbCBpUkJDIiwgIkFzZXh1YWwgaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvdGFsIGFzZXh1YWwgaVJCQyIsICJUb3RhbCBhc2V4dWFsXG5pUkJDIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2V4dWFsIGlSQkMiLCAiU2V4dWFsIGlSQkMgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBc2V4dWFsJnNleHVhbCBpUkJDIiwgIkFzZXh1YWwmc2V4dWFsXG5pUkJDIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVG90YWwgaVJCQyIsICJUb3RhbCBpUkJDIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR2FtZXRvY3l0ZSIsICJHYW1ldG9jeXRlIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVG90YWwgZ2FtZXRvY3l0ZSIsICJUb3RhbCBzZXh1YWwgaVJCQyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlJCQyIsICJSQkMgbG9nMTAiKSkKIyBwbG90CmdncGxvdCgpICsKICBnZW9tX2xpbmUoZGF0YSA9IGNpX3JuLmRmMywgYWVzKHggPSBjdWVfcmFuZ2UsIHkgPSBjciwgY29sb3IgPSAiQ28taW5mZWN0aW9uIikpICsKICBnZW9tX3BvaW50KGRhdGEgPSBjaV9ybi5kZjMgJT4lIAogICAgZ3JvdXBfYnkobGFiZWwpICU+JSAKICAgIG11dGF0ZSh0ZW5fdGggPSByb3VuZChuKCkvMTApKSAlPiUgCiAgICBmaWx0ZXIocm93X251bWJlcigpICUlIHRlbl90aCA9PSAwKSwgYWVzKHggPSBjdWVfcmFuZ2UsIHkgPSBjciwgY29sb3IgPSAiQ28taW5mZWN0aW9uIiwgc2hhcGUgPSAiQ28taW5mZWN0aW9uIiksIHNpemUgPSAyKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBzaV9ybi5kZjMsIGFlcyh4ID0gY3VlX3JhbmdlLCB5ID0gY3IsIGNvbG9yID0gIlNpbmdsZSBpbmZlY3Rpb24iKSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHNpX3JuLmRmMyAlPiUgCiAgICBncm91cF9ieShsYWJlbF9jaSkgJT4lIAogICAgbXV0YXRlKHRlbl90aCA9IHJvdW5kKG4oKS8xMCkpICU+JSAKICAgIGZpbHRlcihyb3dfbnVtYmVyKCkgJSUgdGVuX3RoID09IDApLCBhZXMoeCA9IGN1ZV9yYW5nZSwgeSA9IGNyLCBjb2xvciA9ICJTaW5nbGUgaW5mZWN0aW9uIiwgc2hhcGUgPSAiU2luZ2xlIGluZmVjdGlvbiIpLCBzaXplID0gMikgKwogIGdlb21fcnVnKGRhdGEgPSBjaV9ydWcuZGYzLCBhZXMoeCA9IHZhbHVlKSwgY29sb3IgPSAiIzQ1NzViNCIsIHNpZGVzID0gInQiLCBsZW5ndGggPSB1bml0KDAuMSwgIm5wYyIpKSArCiAgZ2VvbV9ydWcoZGF0YSA9IHNpX3J1Zy5kZjMsIGFlcyh4ID0gdmFsdWUpLCBjb2xvciA9ICIjZmM4ZDU5Iiwgc2lkZXMgPSAiYiIsIGxlbmd0aCA9IHVuaXQoMC4xLCAibnBjIikpICsKICBmYWNldF93cmFwKH5lel9sYWJlbCwgc2NhbGVzID0gImZyZWVfeCIsIG5jb2wgPSAyKSArCiAgeWxpbSgtMC4zLCAxLjMpICsKICB0aGVtZV9idygpICsKICBsYWJzKHkgPSAiQ29udmVyc2lvbiByYXRlIiwgeCA9ICJDdWUgcmFuZ2UiLCBjb2xvciA9ICJNb2RlbCIsIHNoYXBlID0gIk1vZGVsIikgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFQpLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMoY2hlY2sub3ZlcmxhcCA9IFRSVUUpKSArIAogICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA3KSwKICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKSAgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YyggIiM0NTc1YjQiLCAiI2ZjOGQ1OSIpKSArCiAgdGhlbWUoc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbihiID0gMC41LCB0ID0gMC41KSkpCgpnZ3NhdmUodW5pdHMgPSAicHgiLCBkcGkgPSAzMDAsIHdpZHRoID0gMjAwMCwgaGVpZ2h0ID0gMjUwMCwgZmlsZW5hbWUgPSBoZXJlKCJmaWd1cmVzL3Bsb3MtYmlvL3JlYWN0aW9uX25vcm0udGlmZiIpLCBiZyA9ICJ3aGl0ZSIsIHNjYWxlID0gMS4xKQpgYGAKCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKUGxvdHRpbmcgc2luZ2xlIGFuZCBjby1pbmZlY3Rpb24gZml0bmVzcyBzY2F0dGVyIHBsb3QKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwojIGltcG9ydCBpbiBkYXRhCmBgYHtyfQojIHNpbmdsZSBpbmZlY3Rpb24gZHluYW1pY3MKc2lfZHluLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL3NpX2R5bi9zaV9keW5fMzAucGFycXVldCIpKSAKCiMgY28taW5mZWN0aW9uIGR5bmFtaWNzCmNpX2R5bi5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9jaV9keW4vY2lfZHluLnBhcnF1ZXQiKSkKCmV6X2xhYmVsIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvZXpfbGFiZWwuY3N2IikpCmBgYAoKIyBwcm9jZXNzIGZvciBmaW5hbCAyMCBkYXlzIGZpdG5lc3MKYGBge3J9CiMgZ2V0IHNpbmdsZSBpbmZlY3Rpb24gbWF4aW11bSB0YXVfY3VtIGZvciAyMCBkYXlzCnNpX2ZpdG5lc3MuZGYgPC0gc2lfZHluLmRmICU+JSAKICBmaWx0ZXIodmFyaWFibGUgPT0gInRhdV9jdW0iICYgdGltZSA9PSAyMCkKCiMgZ2V0IGNvLWluZmVjdGlvbiBtYXhpbXVtIHRhdV9jdW0gZm9yIDIwIGRheXMKY2lfZml0bmVzcy5kZiA8LSBjaV9keW4uZGYgJT4lIAogIGZpbHRlcih2YXJpYWJsZSA9PSAidGF1X2N1bTEiICYgdGltZSA9PSAyMCkKCiMgam9pbiB0b2dldGhlciB0d28gZGF0YWZyYW1lcyBhbmQgYWRkIGxhYmVscwpzaV9jaV9maXRuZXNzLmRmIDwtIHNlbGVjdChjaV9maXRuZXNzLmRmLCBmaXRuZXNzX2NpID0gdmFsdWUsIGxhYmVsX2NpID0gbGFiZWwpICU+JSAKICBsZWZ0X2pvaW4oZXpfbGFiZWwsIGJ5ID0gImxhYmVsX2NpIikgJT4lIAogIGxlZnRfam9pbihzZWxlY3Qoc2lfZml0bmVzcy5kZiwgZml0bmVzc19zaSA9IHZhbHVlLCBpZF9zaSA9IGlkKSwgYnkgPSAiaWRfc2kiKSAlPiUgCiAgc2VsZWN0KGV6X2xhYmVsX3NpLCBlel9sYWJlbCwgZml0bmVzc19zaSwgZml0bmVzc19jaSkgJT4lIAogIHJiaW5kKGRhdGEuZnJhbWUoICMgYWRkIHRpbWUKICAgIGV6X2xhYmVsX3NpID0gIlRpbWUiLCAKICAgIGV6X2xhYmVsID0gIlRpbWUiLAogICAgZml0bmVzc19zaSA9ICA5Ljc4Nzg5OSwKICAgIGZpdG5lc3NfY2kgID0gMi4zMTE4NDEKICApKQoKc2lfY2lfZml0bmVzcy5kZgpgYGAKCiMgcGxvdCBzY2F0dGVyIHBvaW50IG9mIHNpbmdsZSBpbmZlY3Rpb24gdnMgY28taW5mZWN0aW9uCmBgYHtyfQpzaV9jaV9maXRuZXNzLnBsIDwtIGdncGxvdCgpICsKICBnZW9tX3BvaW50KGRhdGEgPSBzaV9jaV9maXRuZXNzLmRmLCBhZXMoeCA9IGZpdG5lc3Nfc2ksIHkgPSBmaXRuZXNzX2NpLCBjb2xvciA9IGV6X2xhYmVsX3NpLCBzaGFwZSA9IGV6X2xhYmVsX3NpKSwgc2l6ZSA9IDMuNSkgKwogIGdncmVwZWw6Omdlb21fbGFiZWxfcmVwZWwoZGF0YSA9IHNpX2NpX2ZpdG5lc3MuZGYsIGFlcyhsYWJlbCA9IGV6X2xhYmVsLCB4ID0gZml0bmVzc19zaSwgeSA9IGZpdG5lc3NfY2kpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJ3aGl0ZSIseGxpbSA9IGMoLUluZiwgSW5mKSwgeWxpbSA9IGMoTkEsIE5BKSkgKwogIGxhYnMoeCA9ICJNYXhpbXVtIHNpbmdsZSBpbmZlY3Rpb24gZml0bmVzcyIsIHkgPSAiTWF4aW11bSBDby1pbmZlY3Rpb24gZml0bmVzcyAocGVyIHN0cmFpbikiLAogICAgICAgY29sb3IgPSAiU2luZ2xlIGluZmVjdGlvbiBjdWUiLCBzaGFwZSA9ICJTaW5nbGUgaW5mZWN0aW9uIGN1ZSIpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gMTU6MjUpICsKICBsaW1zKHggPSBjKDgsIDEwLjMpKSArCiAgdGhlbWVfYncoKQpgYGAKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIyB0aW1lIHNlcmllcyBjb252ZXJzaW9uIHJhdGUgZm9yIHNpbmdsZSBhbmQgY28taW5mZWN0aW9uCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMtLS0tLS0tLS1nZXQgImlkZWFsIiBzaW5nbGUgaW5mZWN0aW9uIGFuZCBjby1pbmZlY3Rpb24gZHluYW1pY3MtLS0tLS0tLS0jClRoaXMgaXMgd2hlbiBzdHVmZiBhcmUgb3B0aW1pemVkIGJhc2VkIG9uIHRpbWUKYGBge3J9CnNvdXJjZShoZXJlKCJmdW5jdGlvbnMvY2hhYmF1ZGlfc2lfY2xlYW4uUiIpKQpzb3VyY2UoaGVyZSgiZnVuY3Rpb25zL2NoYWJhdWRpX2NpX2NsZWFuLlIiKSkKCiMgc2luZ2xlIGluZmVjdGlvbiBkeW5hbWljIHdpdGggdGltZSBhcyBjdWUuIE9wdGltaXplZCB1c2luZyBsb2NhbCBvcHRpbWl6ZXIuIE5vdGUgdGhhdCB0aGUgdGltZSB2YXJpYWJsZSBpbiBkdWFsIGN1ZSBpcyBzbGlnaHRseSBkaWZmZXJlbnQgd2l0aCBoaWdoZXIgZmxleGliaWxpdHkuIFdoaWxlIHRoYXQgaW5jcmVhc2VzIHRoZSBmaXRuZXNzIHZhbHVlIGJ5IH4wLjEsIHRoZSBvdmVyYWxsIGNvbnZlcnNpb24gcmF0ZSBkeW5hbWljIGRvZXMgbm90IGNoYW5nZSB0aGF0IG11Y2gKc2lfdC5kZiA8LSBjaGFiYXVkaV9zaV9jbGVhbigKICBwYXJhbWV0ZXJzX2NyID0gYyg0LjU1Mzg2LCAtMTMuMDA1NiwgNC4xNTQ2NiwgLTExLjk0MjQpLAogIGltbXVuaXR5ID0gInRzdWt1c2hpIiwKICBwYXJhbWV0ZXJzID0gcGFyYW1ldGVyc190c3VrdXNoaSwKICB0aW1lX3JhbmdlID0gc2VxKDAsIDIwLCBieSA9IDFlLTMpLAogIGN1ZV9yYW5nZSA9ICBzZXEoMCwgMjAsIGJ5ID0gMWUtMyksCiAgY3VlID0gInQiLAogIHNvbHZlciA9ICJ2b2RlIiwKICBkeW4gPSBUKQoKIyBjby1pbmZlY3Rpb24gZHluYW1pYyB3aXRoIHRpbWUgYXMgY3VlCmNpX3QuZGYgPC0gY2hhYmF1ZGlfY2lfY2xlYW4ocGFyYW1ldGVyc19jcl8xID0gYygyNi4xNjQyNSwJLTcxLjA3Nzk5LAk1My4zNDEyMSwJLTE2Ni4yNTY5MyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbWV0ZXJzX2NyXzIgPSBjKDI2LjE2NDI1LAktNzEuMDc3OTksCTUzLjM0MTIxLAktMTY2LjI1NjkzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGltbXVuaXR5ID0gInRzdWt1c2hpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtZXRlcnMgPSBwYXJhbWV0ZXJzX3RzdWt1c2hpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGltZV9yYW5nZSA9IHRpbWVfcmFuZ2UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VlXzEgPSAgInQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VlXzI9ICJ0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1ZV9yYW5nZV8xID0gdGltZV9yYW5nZSwgIyBjdWUgcmFuZ2Ugb2Ygc3RyYWluIDEKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1ZV9yYW5nZV8yID0gdGltZV9yYW5nZSwgIyBjdWUgcmFuZ2Ugb2Ygc3RyYWluIDIKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ19jdWVfMSA9ICJub25lIiwgIyB3aGV0aGVyIHRvIGxvZyB0cmFuc2Zvcm0gY3VlIDEKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ19jdWVfMiA9ICJub25lIiwgIyB3aGV0aGVyIHRvIGxvZyB0cmFuc2Zvcm0gY3VlIDIKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNvbHZlciA9ICJ2b2RlIiwgIyBzb2x2ZXIgZm9yIG51bWVyaWNhbCBpbnRlZ3JhdGlvbi4gVm9kZSBvZnRlbiBnaXZlcyBmYXN0ZXIgcnVucwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkeW4gPSBUKQoKIyBnZXQgb25seSBjb252ZXJzaW9uIHJhdGUgYW5kIG1ha2Ugc2FtZSBmb3JtYXQgYXMgc2lfY3IuZGYyL2NpX2NyLmRmMgpzaV90LmRmICU+JSBmaWx0ZXIodGltZSA9PSAyMCAmIHZhcmlhYmxlID09ICJ0YXVfY3VtIikgIyMgZml0bmVzcyB2YWx1ZSBvZiB0aW1lIGFzIGN1ZSBpbiBzaW5nbGUgaW5mZWN0aW9uCnNpX3QuY3IgPC0gc2lfdC5kZiAlPiUgCiAgZmlsdGVyKHZhcmlhYmxlID09ICJjciIpICU+JSAKICBtdXRhdGUoZXpfbGFiZWxfc2kgPSAiVGltZSIsIAogICAgICAgICBmaXRuZXNzX3NpID05Ljc4Nzg5OSkgJT4lIAogIHNlbGVjdCh0aW1lLCB2YWx1ZSwgZml0bmVzc19zaSwgZXpfbGFiZWxfc2kpCgoKIyMgZ2V0IGZpdG5lc3MgdmFsdWUgb2YgY28taW5mZWN0aW9uIHRpbWUKY2lfdC5kZiAlPiUgZmlsdGVyKHRpbWUgPT0gMjAgJiB2YXJpYWJsZSA9PSAidGF1X2N1bTEiKSAjIyBGSVRORVNTIFZBTFVFIE9GIFRJTUUgQVMgQ1VFIElOIENPLUlORkVDVElPTgpjaV90LmNyIDwtIGNpX3QuZGYgJT4lIAogIGZpbHRlcih2YXJpYWJsZSA9PSAiY3JfMSIpICU+JSAKICBtdXRhdGUoZXpfbGFiZWwgPSAiVGltZSIsIAogICAgICAgICBmaXRuZXNzX2NpID0gMi4zMTE4NDEpICU+JQogIHNlbGVjdCh0aW1lLCB2YWx1ZSwgZml0bmVzc19jaSwgZXpfbGFiZWwpCgpgYGAKCiMtLS0tLS0tLS0gc2luZ2xlIGluZmVjdGlvbiBjb252ZXJzaW9uIHJhdGUgaGVhdCBtYXAtLS0tLS0tLS0tLS0tLSMKIyBwcm9jZXNzIGluZm8gZm9yIHNpbmdsZSBpbmZlY3Rpb24KYGBge3J9CiMgZ2V0IGNvbnZlcnNpb24gcmF0ZSBkeW5hbWljcwpzaV9jci5kZiA8LSBzaV9keW4uZGYgJT4lIAogIGZpbHRlcih0aW1lIDw9IDIwICYgdmFyaWFibGUgPT0gImNyIikKCgojIGpvaW4gd2l0aCBjbGFzc2lmaWNhaXRvbgpzaV9jci5kZjIgPC0gc2lfY3IuZGYgJT4lIAogIGxlZnRfam9pbihzZWxlY3Qoc2lfZml0bmVzcy5kZiwgaWQsIGZpdG5lc3Nfc2kgPSB2YWx1ZSksIGJ5ID0gImlkIikgJT4lIAogIGxlZnRfam9pbihlel9sYWJlbCwgYnkgPSBjKCJpZCIgPSAiaWRfc2kiKSkgJT4lIAogIHNlbGVjdCh0aW1lLCB2YWx1ZSwgZml0bmVzc19zaSwgZXpfbGFiZWxfc2kpICU+JSAKICByYmluZChzaV90LmNyKSAjIGpvaW4gd2l0aCBkYXRhZnJhbWUgY29udGFpbmluZyBpZGVhbCBkeW5hbWljcwoKIyBwbG90CnNpX2NyLnBsIDwtIGdncGxvdChkYXRhID0gc2lfY3IuZGYyLCBhZXMoeCA9IHRpbWUsIHkgPSBmb3JjYXRzOjpmY3RfcmVvcmRlcihlel9sYWJlbF9zaSwgZml0bmVzc19zaSkpKSArCiAgZ2VvbV9yYXN0ZXIoYWVzKGZpbGwgPSB2YWx1ZSkpICsKICBsYWJzKHggPSAiVGltZSAoZGF5cykiLCB5ID0gIlNpbmdsZSBpbmZlY3Rpb24gY3VlcyIsIGZpbGwgPSAiQ29udmVyc2lvbiByYXRlIikgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKGxpbWl0cyA9IGMoMCwgMSkpICsKICB4bGltKDEsIDIwKSArCiAgdGhlbWVfYncoKQpgYGAKCiMgLS0tLS0tLS0tLS0tLS0tLS1jby1pbmZlY3Rpb24gY29udmVyc2lvbiByYXRlIGhlYXRtYXAtLS0tLS0tLS0tLSMKIyBwbG90IGNvLWluZmVjaXRvbiBjb252ZXNpb24gcmF0ZSBoZWF0bWFwCmBgYHtyfQojIGdldCBjb252ZXJzaW9uIHJhdGUgZHluYW1pY3MKY2lfY3IuZGYgPC0gY2lfZHluLmRmICU+JSAKICBmaWx0ZXIodGltZSA8PSAyMCAmIHZhcmlhYmxlID09ICJjcl8xIikKCiMgam9pbiB3aXRoIGNsYXNzaWZpY2FpdG9uCmNpX2NyLmRmMiA8LSBjaV9jci5kZiAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChjaV9maXRuZXNzLmRmLCBsYWJlbCwgZml0bmVzc19jaSA9IHZhbHVlKSwgYnkgPSAibGFiZWwiKSAlPiUgCiAgbGVmdF9qb2luKGV6X2xhYmVsLCBieSA9IGMoImxhYmVsIiA9ICJsYWJlbF9jaSIpKSAlPiUgCiAgc2VsZWN0KHRpbWUsIHZhbHVlLCBmaXRuZXNzX2NpLCBlel9sYWJlbCkgJT4lIAogIHJiaW5kKGNpX3QuY3IpICMgYmluZCB0aW1lCgojIHBsb3QKY2lfY3IucGwgPC0gZ2dwbG90KCkgKwogIGdlb21fcmFzdGVyKGRhdGEgPSBjaV9jci5kZjIsIGFlcyh4ID0gdGltZSwgeSA9IGZvcmNhdHM6OmZjdF9yZW9yZGVyKGV6X2xhYmVsLCBmaXRuZXNzX2NpKSwgZmlsbCA9IHZhbHVlKSwgYWxwaGEgPSAxKSArCiAgbGFicyh4ID0gIlRpbWUgKGRheXMpIiwgeSA9ICJDby1pbmZlY3Rpb24gY3VlcyIsIGZpbGwgPSAiQ29udmVyc2lvbiByYXRlIikgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKGxpbWl0cyA9IGMoMCwgMSkpICsKICB4bGltKDEsIDIwKSArCiAgdGhlbWVfYncoKQpgYGAKCiMtLS0tLS0tLS0gYXNzZW1ibGUgZmluYWwgZmlndXJlIC0tLS0tLS0tLS0tLS0tIwpgYGB7cn0KIyBjb21iaW5lIGNvbnZlcnNpb24gcmF0ZSBkeW5hbWljIG9mIHNpbmdsZSBpbmZlY3Rpb24gYW5kIGNvLWluZmVjdGlvbgpjci5wbCA8LSBnZ2FycmFuZ2Uoc2lfY3IucGwsIGNpX2NyLnBsLCBsYWJlbHMgPSBjKCJCIiwgIkMiKSwgbmNvbCA9IDIsIGNvbW1vbi5sZWdlbmQgPSBULCBhbGlnbiA9ICJoIikKCiMgY29tYmluZSB3aXRoIGZpdG5lc3Mgc2NhdHRlcnBsb3QKZ2dhcnJhbmdlKHNpX2NpX2ZpdG5lc3MucGwsIGNyLnBsLCBuY29sID0gMSwgbGFiZWxzID0gYygiQSIsICIiKSwgYWxpZ24gPSAiaHYiKQoKIyBzYXZlCmdnc2F2ZSh1bml0cyA9ICJweCIsIGRwaSA9IDMwMCwgd2lkdGggPSAyMDAwLCBoZWlnaHQgPSAyMDAwLCBmaWxlbmFtZSA9IGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vZml0bmVzc19jci1keW4udGlmZiIpLCBiZyA9ICJ3aGl0ZSIsIHNjYWxlID0gMS4zNSkKYGBgCgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMgRGVtb2dyYXBoaWMgc3RvY2hhc3RpY2l0eQojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMtLS0tLS0tLS0tIHBsb3QgaGVhdCBtYXAtLS0tLS0tLS0tLS0tLS0jCiMgaW1wb3J0IGluIGFsbCBmaXRuZXNzIGZpbGVzCmBgYHtyfQpmaWxlX2xzIDwtIGxpc3QuZmlsZXMocGF0aCA9IGhlcmUoImRhdGEvTUNfcGFydGl0aW9uZWQvIiksIHBhdHRlcm4gPSAiKi5jc3YiLCBmdWxsLm5hbWVzID0gVCkKbmFtZV9scyA8LSBsaXN0LmZpbGVzKHBhdGggPSBoZXJlKCJkYXRhL01DX3BhcnRpdGlvbmVkLyIpLCBwYXR0ZXJuID0gIiouY3N2IikKbmFtZV9scyA8LSBnc3ViKCIqLmNzdiIsICIiLCBuYW1lX2xzKQoKIyA2MCwgd2hpY2ggaXMgYWJvdXQgcmlnaHQKbGVuZ3RoKGZpbGVfbHMpCgojIHJlYWQgaW4gZmlsZXMKZml0bmVzcy5scyA8LSBsYXBwbHkoZmlsZV9scywgcmVhZC5jc3YpCgojIGFzc2lnbiB1bmlxdWUgSUQKZml0bmVzcy5scyA8LSBtYXBwbHkoY2JpbmQsIGZpdG5lc3MubHMsICJJRCIgPSBuYW1lX2xzLCBTSU1QTElGWSA9IEYpCmBgYAoKIyBwcm9jZXNzIGRhdGEKYGBge3J9CiMgZ2V0IG1ldGFpbmZvIGZyb20gSUQKZml0bmVzcy5sczIgPC0gbWNsYXBwbHkoZml0bmVzcy5scywgZnVuY3Rpb24oeCl7CiAgaWRfY29sIDwtIHgkSUQKICAjIHN0cmluZyBzcGxpdCB0byBleHRyYWN0IGFsbCBpbmZvCiAgY3VlIDwtIHVubGlzdChzdHJfc3BsaXQodW5pcXVlKGlkX2NvbCksIHBhdHRlcm4gPSAiXyIpKVtbM11dCiAgbG9nIDwtIHVubGlzdChzdHJfc3BsaXQodW5pcXVlKGlkX2NvbCksIHBhdHRlcm4gPSAiXyIpKVtbNF1dCiAgcmFuZF92YXIgPC0gdW5saXN0KHN0cl9zcGxpdCh1bmlxdWUoaWRfY29sKSwgcGF0dGVybiA9ICJfIikpW1s1XV0KICAKICAjIGdldCBtZWFuCiAgbWVhbl9maXRuZXNzIDwtIG1lYW4oeCRtYXhfZml0bmVzcykKICAjIGdldCBzZAogIHNkX2ZpdG5lc3MgPC0gc2QoeCRtYXhfZml0bmVzcykKICAKICAjIGJpbmQgcmVzdWx0cwogIHJlcyA8LSBjYmluZCh4LCBjdWU9IGN1ZSwgbG9nID0gbG9nLCByYW5kX3ZhciA9IHJhbmRfdmFyLCBtZWFuX2ZpdG5lc3MgPSBtZWFuX2ZpdG5lc3MsIHNkX2ZpdG5lc3MgPSBzZF9maXRuZXNzKQogIHJldHVybihyZXMpCn0pCmBgYAoKIyBHZXQgcmVmZXJlbmNlIGRhdGEKYGBge3J9CnJlZmVyZW5jZV9scyA8LSBsaXN0LmZpbGVzKHBhdGggPSBoZXJlKCJkYXRhL01DMiIpLCBwYXR0ZXJuID0gIiouY3N2IiwgZnVsbC5uYW1lcyA9IFQpCnJlZmVyZW5jZV9uYW1lLmxzIDwtIGdzdWIoIiouY3N2IiwgIiIsIGxpc3QuZmlsZXMocGF0aCA9IGhlcmUoImRhdGEvTUMyLyIpLCBwYXR0ZXJuID0gIiouY3N2IikpCgojIHJlYWQgaW4gdGhlIGZpbGVzCnJlZmVyZW5jZS5scyA8LSBsYXBwbHkocmVmZXJlbmNlX2xzLCByZWFkLmNzdikKCiMgYXNzaWduIHVuaXF1ZSBJRApyZWZlcmVuY2UubHMgPC0gbWFwcGx5KGNiaW5kLCByZWZlcmVuY2UubHMsICJJRCIgPSByZWZlcmVuY2VfbmFtZS5scywgU0lNUExJRlkgPSBGKQoKIyBnZXQgbWV0YSBkYXRhCnJlZmVyZW5jZS5sczIgPC0gbWNsYXBwbHkocmVmZXJlbmNlLmxzLCBmdW5jdGlvbih4KXsKICBpZF9jb2wgPC0geCRJRAogICMgc3RyaW5nIHNwbGl0IHRvIGV4dHJhY3QgYWxsIGluZm8KICBjdWUgPC0gdW5saXN0KHN0cl9zcGxpdCh1bmlxdWUoaWRfY29sKSwgcGF0dGVybiA9ICJfIikpW1syXV0KICAjIGdldCBsb2cKICB0aGlyZF9jb2wgPC0gdW5saXN0KHN0cl9zcGxpdCh1bmlxdWUoaWRfY29sKSwgcGF0dGVybiA9ICJfIikpW1szXV0KICBsb2cgPC0gaWZlbHNlKHRoaXJkX2NvbCA9PSAibG9nIiwgImxvZzEwIiwgIm5vbmUiKQogIAogICMgZ2V0IG1lYW4KICBtZWFuX2ZpdG5lc3MgPC0gbWVhbih4JG1heF9maXRuZXNzKQogIAogICMgZ2V0IHNkCiAgc2RfZml0bmVzcyA8LSBzZCh4JG1heF9maXRuZXNzKQogIAogICMgYmluZCByZXN1bHRzCiAgcmVzIDwtIGNiaW5kKHgsIGN1ZT0gY3VlLCBsb2cgPSBsb2csIHJhbmRfdmFyID0gImFsbCIsIHJlZl9tZWFuX2ZpdG5lc3MgPSBtZWFuX2ZpdG5lc3MsIHJlZl9zZF9maXRuZXNzID0gc2RfZml0bmVzcykKICByZXR1cm4ocmVzKQp9KQpgYGAKCiMgY29tYmluZSBNQyBwYXJ0aXRpb25lZCBhbmQgcmVmZXJlbmNlIGRmCmBgYHtyfQojIGdldCB1bmlxdWUgY29sdW1uIHZhbHVlcyBmb3IgZWFjaCBjdWUsIGxvZywgYW5kIHJhbmRfdmFyIGNvbWJvCmZpdG5lc3MubHMzIDwtIGRvLmNhbGwocmJpbmQsIGZpdG5lc3MubHMyKQpmaXRuZXNzLmxzMyA8LSBmaXRuZXNzLmxzMyAlPiUgZHBseXI6OmRpc3RpbmN0KElELCAua2VlcF9hbGwgPSBUKQoKIyByZXBlYXQgd2l0aCByZWZlcmVuY2UKcmVmZXJlbmNlLmxzMyA8LSBkby5jYWxsKHJiaW5kLCByZWZlcmVuY2UubHMyKQpyZWZlcmVuY2UubHMzIDwtIHJlZmVyZW5jZS5sczMgJT4lIGRwbHlyOjpkaXN0aW5jdChJRCwgLmtlZXBfYWxsID0gVCkKCiMgY29tYmluZSEKcmVmX2ZpdC5kZiA8LSBsZWZ0X2pvaW4oZml0bmVzcy5sczMsIHJlZmVyZW5jZS5sczMsIGJ5ID0gYygiY3VlIiA9ICJjdWUiLCAibG9nIj0gImxvZyIpKQpgYGAKCiMgY29tcHV0ZSBwcm9wb3J0aW9uIGZpdG5lc3MgYW5kIHZhcmlhdGlvbgpgYGB7cn0KcmVmX2ZpdC5kZjIgPC0gcmVmX2ZpdC5kZiAlPiUgCiAgbXV0YXRlKHBfc2QgPSBzZF9maXRuZXNzL3JlZl9zZF9maXRuZXNzLAogICAgICAgICBwX21lYW4gPSByZWZfbWVhbl9maXRuZXNzL21lYW5fZml0bmVzcywKICAgICAgICAgY3VlX2xvZyA9IHBhc3RlMChjdWUsICJfIiwgbG9nKSwKICAgICAgICAgbGFiZWwgPSBjYXNlX3doZW4oCiAgICAgICAgICAgY3VlID09ICJHIiB+ICJHYW1ldG9jeXRlIiwKICAgICAgICAgICBjdWUgPT0gIkkiIH4gIkFzZXh1YWwgaVJCQyIsCiAgICAgICAgICAgY3VlID09ICJJK0lnIiB+ICJBc2V4dWFsJnNleHVhbFxuaVJCQyIsCiAgICAgICAgICAgY3VlID09ICJJZyIgfiAiU2V4dWFsIGlSQkMiLAogICAgICAgICAgIGN1ZSA9PSAiUiIgfiAiUkJDIgogICAgICAgICAgICksCiAgICAgICAgIHBhcmFtZXRlciA9IGNhc2Vfd2hlbigKICAgICAgICAgICByYW5kX3Zhci54ID09ICJyaG8iIH4gIs+BIiwKICAgICAgICAgICByYW5kX3Zhci54ID09ICJwaGluIiB+ICLPlW4iLAogICAgICAgICAgIHJhbmRfdmFyLnggPT0gInBoaXcifiAiz5V3IiwKICAgICAgICAgICByYW5kX3Zhci54ID09ICJwc2luIiB+ICLPiG4iLAogICAgICAgICAgIHJhbmRfdmFyLnggPT0gInBzaXciIH4gIs+IdyIsCiAgICAgICAgICAgcmFuZF92YXIueCA9PSAiYmV0YSIgfiAizrIiCiAgICAgICAgICkpCmBgYAoKIyBwbG90IQpgYGB7cn0KIyB2YXJpYXRpb24KbWNfYiA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV90aWxlKGRhdGEgPSByZWZfZml0LmRmMiAsIGFlcyh4ID0gbGFiZWwsIHkgPSBwYXJhbWV0ZXIsIGZpbGwgPSBwX3NkKSkgKwogIGZhY2V0X3dyYXAofmxvZykgKwogIHRoZW1lX2J3KCkgKwogIHZpcmlkaXM6OnNjYWxlX2ZpbGxfdmlyaWRpcygpICsKICBsYWJzKHggPSAiQ3VlIiwgeSA9ICJQYXJhbWV0ZXIgcmFuZG9taXplZCIsIGZpbGwgPSBleHByZXNzaW9uKGZyYWMoc2QoIjEgcGFyYW1ldGVyIHJhbmRvbWl6ZWQiKSwgc2QoImFsbCBwYXJhbWV0ZXJzIHJhbmRvbWl6ZWQiKSkpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0PTEpKQoKIyBtZWFuIGZpdG5lc3MKbWNfYyA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV90aWxlKGRhdGEgPSByZWZfZml0LmRmMiAsIGFlcyh4ID0gbGFiZWwsIHkgPSBwYXJhbWV0ZXIsIGZpbGwgPSBwX21lYW4pKSArCiAgZmFjZXRfd3JhcCh+bG9nKSArCiAgdGhlbWVfYncoKSArCiAgdmlyaWRpczo6c2NhbGVfZmlsbF92aXJpZGlzKCkgKwogIGxhYnMoeCA9ICJDdWUiLCB5ID0gIlBhcmFtZXRlciByYW5kb21pemVkIiwgZmlsbCA9IGV4cHJlc3Npb24oZnJhYyhNZWFuKCJhbGwgcGFyYW1ldGVycyByYW5kb21pemVkIiksIE1lYW4oIjEgcGFyYW1ldGVyIHJhbmRvbWl6ZWQiKSkpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0PTEpKQoKbWNfcGFydGl0aW9uIDwtIGdnYXJyYW5nZShtY19iLCBtY19jLCBuY29sID0gMSkKCmBgYAoKIy0tLS0tLS0tLS0tLS0tIGdldCB2aW9saW5lIHBsb3Qgb2YgdmFyaWF0aW9uIGluIGZpdG5lc3MgLS0tLS0tLS0tLS0tLS0tLS0tLS0jCiMgcmVhZCBNQyBkYXRhCmBgYHtyfQojIHJlYWQgaW4gZHltYW1pY3MKbWNfR19sb2cuZHluIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL01DMi9tY19HX2xvZ19keW4ucGFycXVldCIpKQptY19HLmR5biA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9NQzIvbWNfR19keW4ucGFycXVldCIpKQptY19SX2xvZy5keW4gPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvTUMyL21jX1JfbG9nX2R5bi5wYXJxdWV0IikpCm1jX1IuZHluIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL01DMi9tY19SX2R5bi5wYXJxdWV0IikpCm1jX0lfbG9nLmR5biA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9NQzIvbWNfSV9sb2dfZHluLnBhcnF1ZXQiKSkKbWNfSS5keW4gPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvTUMyL21jX0lfZHluLnBhcnF1ZXQiKSkKbWNfSWdfbG9nLmR5biA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9NQzIvbWNfSWdfbG9nX2R5bi5wYXJxdWV0IikpCm1jX0lnLmR5biA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9NQzIvbWNfSWdfZHluLnBhcnF1ZXQiKSkKbWNfSV9JZ19sb2cuZHluIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL01DMi9tY19JK0lnX2xvZ19keW4ucGFycXVldCIpKQptY19JX0lnLmR5biA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9NQzIvbWNfSStJZ19keW4ucGFycXVldCIpKQoKIyByZWFkIGluIGZpdG5lc3MKbWNfR19sb2cuZml0bmVzcyA8LSByZWFkLmNzdihoZXJlKCJkYXRhL01DMi9tY19HX2xvZ19maXRuZXNzLmNzdiIpKQptY19HLmZpdG5lc3MgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9NQzIvbWNfR19maXRuZXNzLmNzdiIpKQptY19SX2xvZy5maXRuZXNzIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvTUMyL21jX1JfbG9nX2ZpdG5lc3MuY3N2IikpCm1jX1IuZml0bmVzcyA8LSByZWFkLmNzdihoZXJlKCJkYXRhL01DMi9tY19SX2ZpdG5lc3MuY3N2IikpCm1jX0lfbG9nLmZpdG5lc3MgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9NQzIvbWNfSV9sb2dfZml0bmVzcy5jc3YiKSkKbWNfSS5maXRuZXNzIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvTUMyL21jX0lfZml0bmVzcy5jc3YiKSkKbWNfSWdfbG9nLmZpdG5lc3MgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9NQzIvbWNfSWdfbG9nX2ZpdG5lc3MuY3N2IikpCm1jX0lnLmZpdG5lc3MgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9NQzIvbWNfSWdfZml0bmVzcy5jc3YiKSkKbWNfSV9JZ19sb2cuZml0bmVzcyA8LSByZWFkLmNzdihoZXJlKCJkYXRhL01DMi9tY19JK0lnX2xvZ19maXRuZXNzLmNzdiIpKQptY19JX0lnLmZpdG5lc3MgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9NQzIvbWNfSStJZ19maXRuZXNzLmNzdiIpKQpgYGAKCiMgZXhhbWluZSB2YXJpYXRpb24KYGBge3J9CiMgcGxvdCBmaXRuZXNzIHZzIGl0ZXJhdGlvbgpmaXRuZXNzLmRmIDwtIHJiaW5kKAogIGNiaW5kKG1jX0dfbG9nLmZpdG5lc3MsIGlkID0gIkdhbWV0b2N5dGVcbmxvZzEwIiksCiAgY2JpbmQobWNfRy5maXRuZXNzLCBpZCA9ICJHYW1ldG9jeXRlIiksCiAgY2JpbmQobWNfUl9sb2cuZml0bmVzcywgaWQgPSAiUkJDIGxvZzEwIiksCiAgY2JpbmQobWNfUi5maXRuZXNzLCBpZCA9ICJSQkMiKSwKICBjYmluZChtY19JX2xvZy5maXRuZXNzLCBpZCA9ICJBc2V4dWFsIGlSQkNcbmxvZzEwIiksCiAgY2JpbmQobWNfSS5maXRuZXNzLCBpZCA9ICJBc2V4dWFsIGlSQkMiKSwKICBjYmluZChtY19JZ19sb2cuZml0bmVzcywgaWQgPSAiU2V4dWFsIGlSQkNcbmxvZzEwIiksCiAgY2JpbmQobWNfSWcuZml0bmVzcywgaWQgPSAiU2V4dWFsIGlSQkMiKSwKICBjYmluZChtY19JX0lnX2xvZy5maXRuZXNzLCBpZCA9ICJBc2V4dWFsJnNleHVhbCBpUkJDXG5sb2cxMCIpLAogIGNiaW5kKG1jX0lfSWcuZml0bmVzcywgaWQgPSAiQXNleHVhbCZzZXh1YWxcbmlSQkMiKQopCgojIHF1YW50aWZ5IHZhcmlhbmNlIGFuZCBtZWFuCmZpdG5lc3NfdmFyLmRmIDwtIGZpdG5lc3MuZGYgJT4lIAogIGRwbHlyOjpncm91cF9ieShpZCkgJT4lIAogIGRwbHlyOjpzdW1tYXJpc2UobWVkaWFuID0gbWVkaWFuKG1heF9maXRuZXNzKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoaWQgPSBmb3JjYXRzOjpmY3RfcmVvcmRlcihpZCwgbWVkaWFuKSkKYGBgCgojIHBsb3QgdmlvbGluIHdpdGggZGlmZmVyZW5jZSBpbiBkZXRlcm1pbmlzdGljIG1vZGVsIGZpdG5lc3MgYW5kIG1lYW4gbW9kZWwgZml0bmVzcwpgYGB7cn0KIyBnZXQgZGV0ZXJtaW5pc3RpYyBkZgpkZXQuZGYgPC0gZGF0YS5mcmFtZShmaXRuZXNzX3Zhci5kZiwgYE1heGltdW0gZml0bmVzc2AgPSAgYyg4LjQ5Nzc3LCA5LjQ5NDk5MSw4Ljg1NDY4Miw5LjU3MzI5MSw4LjU4ODU2LDkuNTYxMzczLDguMjM5OTEsOC4xODE2MDQsOC41NjkyODUsOS42MTg4MTIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShpZCA9IGZvcmNhdHM6OmZjdF9yZW9yZGVyKGlkLCBtZWRpYW4pKSAlPiUgCiAgdGlkeXI6OnBpdm90X2xvbmdlcigtaWQpICU+JSAKICBtdXRhdGUoY2xhc3NpZmljYXRpb24gPSBpZmVsc2UobmFtZSA9PSAiTWF4aW11bS5maXRuZXNzIiwgIk9wdGltYWwgc2luZ2xlIGluZmVjdGlvbiIsICJNZWRpYW4gTW9udGUgQ2FybG8iKSkKCm1jX2EgPC0gZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGRldC5kZiwgYWVzKHkgPSBpZCwgeCA9IHZhbHVlLCBzaGFwZSA9IGNsYXNzaWZpY2F0aW9uLCBjb2xvciA9IGNsYXNzaWZpY2F0aW9uKSwgc2l6ZSA9IDMpICsKICBnZW9tX3Zpb2xpbihkYXRhID0gZml0bmVzcy5kZiwgYWVzKHkgPSBpZCwgeCA9IG1heF9maXRuZXNzKSwgZmlsbCA9ICJ0cmFuc3BhcmVudCIpICsKICBsYWJzKHggPSAiRml0bmVzcyIsIHkgPSAiQ3VlIiwgY29sb3IgPSAiRml0bmVzcyIsIHNoYXBlID0gIkZpdG5lc3MiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoICIjNDU3NWI0IiwgIiNmYzhkNTkiKSkKYGBgCgojLS0tLS0tLS0tLS0tLS0gcGxvdCB0b2dldGhlci0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIwpgYGB7cn0KIyBhcnJhbmdlIHRoZSBoZWF0IG1hcApnZ2FycmFuZ2UobWNfYSwgbWNfcGFydGl0aW9uLCBoZWlnaHRzID0gYygwLjQsIDAuNiksIG5jb2wgPSAxLCBsYWJlbHMgPSBjKCJBIiwgIkIiKSkKCiMgc2F2ZQpnZ3NhdmUodW5pdHMgPSAicHgiLCBkcGkgPSAzMDAsIHdpZHRoID0gMTAwMCwgaGVpZ2h0ID0gMjAwMCwgZmlsZW5hbWUgPSBoZXJlKCJmaWd1cmVzL3Bsb3MtYmlvL01DLnRpZmYiKSwgYmcgPSAid2hpdGUiLCBzY2FsZSA9IDEuOCkKYGBgCgoKCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSMKIyBkdWFsIGN1ZSBvcHRpbWl6YXRpb24gZmlndXJlCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSMKYGBge3J9CnNvdXJjZShoZXJlKCJmdW5jdGlvbnMvY2hhYmF1ZGlfc2lfY2xlYW5faGlnaC5SIikpCnNvdXJjZShoZXJlKCJmdW5jdGlvbnMvY2hhYmF1ZGlfc2lfY2xlYW4uUiIpKQpzb3VyY2UoaGVyZSgiZnVuY3Rpb25zL3Bhcl90b19obV90ZS5SIikpCmBgYAoKIy0tLS0tLS0tLS0gcGxvdHRpbmcgZml0bmVzcyBvZiBkdWFsIHZzIHNpbmdsZSBjdWUgb3B0IC0tLS0tLS0tLSMKIyBpbXBvcnQgaW4gcHJldmlvdXMgZGF0YQpgYGB7cn0KIyBkdWFsIGN1ZSBmaXRuZXNzCmR1YWxfZml0bmVzcy5kZiA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2R1YWxfY3VlX29wdDQvZHVhbF9jdWVfZml0bmVzc18yMC5jc3YiKSkKIyMgbWFrZSBsYWJlbCBhbmQgZmlsdGVyIG91dCB2ZXJ5IGxvdyBmaXRuZXNzCmR1YWxfZml0bmVzcy5kZiA8LSBkdWFsX2ZpdG5lc3MuZGYgJT4lIAogIG11dGF0ZSh0ZW1wX2xhYmVsID0gZ3N1YigibG9nIiwgImxvZzEwIiwgbGFiZWwpLAogICAgICAgICB0ZW1wX2xhYmVsX2IgPSBnc3ViKCJsb2ciLCAibG9nMTAiLCBsYWJlbF9iKSwKICAgICAgICAgbGFiZWxfZmluYWwgPSBwYXN0ZTAodGVtcF9sYWJlbCwgIisiLCB0ZW1wX2xhYmVsX2IpKSAlPiUgCiAgZmlsdGVyKHZhbHVlID4gMikKCiMgZ2V0IHNpbmdsZSBjdWUgZml0bmVzcwpzaV9keW4uZGYgPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvc2lfZHluL3NpX2R5bl8zMC5wYXJxdWV0IikpIApzaV9maXRuZXNzLmRmIDwtIHNpX2R5bi5kZiAlPiUgCiAgZmlsdGVyKHZhcmlhYmxlID09ICJ0YXVfY3VtIiAmIHRpbWUgPT0gMjApCgojIGpvaW4gc2kgYW5kIGR1YWwgY3VlCmR1YWxfc2lfZml0bmVzcy5kZiA8LSBkdWFsX2ZpdG5lc3MuZGYgJT4lIAogIGxlZnRfam9pbihzZWxlY3Qoc2lfZml0bmVzcy5kZiwgaWQsIHNpX2ZpdG5lc3MgPSB2YWx1ZSksIGJ5ID0gImlkIikgJT4lIAogIGxlZnRfam9pbihzZWxlY3Qoc2lfZml0bmVzcy5kZiwgaWRfYiA9IGlkLCBzaV9maXRuZXNzX2IgPSB2YWx1ZSksIGJ5ID0gImlkX2IiKSAlPiUgCiAgbXV0YXRlKHNpX2ZpdG5lc3NfbWF4ID0gaWZlbHNlKHNpX2ZpdG5lc3MgPiBzaV9maXRuZXNzX2IsIHNpX2ZpdG5lc3MsIHNpX2ZpdG5lc3NfYiksCiAgICAgICAgIGR1YWxfbGFiZWwgPSBnc3ViKCJsb2ciLCAibG9nMTAiLCBwYXN0ZShsYWJlbCwgIisiLCBsYWJlbF9iKSkpCmBgYAoKIyBwbG90CmBgYHtyfQpkdWFsX3NpX2ZpdG5lc3MucGwgPC0gZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGR1YWxfc2lfZml0bmVzcy5kZiwgYWVzKHkgPSBmb3JjYXRzOjpmY3RfcmVvcmRlcihkdWFsX2xhYmVsLCB2YWx1ZSksIHggPSB2YWx1ZSwgY29sb3IgPSAiRHVhbCBjdWUiLCBzaGFwZSA9ICJEdWFsIGN1ZSIpLCBzaXplID0gMywgYWxwaGEgPSAwLjcpICsKICBnZW9tX3BvaW50KGRhdGEgPSBkdWFsX3NpX2ZpdG5lc3MuZGYsIGFlcyh5ID0gZm9yY2F0czo6ZmN0X3Jlb3JkZXIoZHVhbF9sYWJlbCwgdmFsdWUpLCB4ID0gc2lfZml0bmVzc19tYXgsIGNvbG9yPSAiQmVzdCBzaW5nbGUgY3VlIiwgc2hhcGU9ICJCZXN0IHNpbmdsZSBjdWUiKSwgc2l6ZSA9IDMsIGFscGhhID0gMC43KSArCiAgbGFicyh4ID0gIkZpdG5lc3MiLCB5ID0gIkR1YWwgY3VlIiwgY29sb3IgPSAiQ3VlIiwgc2hhcGUgPSAiQ3VlIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiI2ZjOGQ1OSIsICIjNDU3NWI0IikpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSA5Ljg4MzYwMikgKwogIGdlb21fdGV4dChhZXMoeD05Ljg4MzYwMiwgbGFiZWw9IlxuSWRlYWwgZml0bmVzcyAoZGY9OSkiLCB5ID0gIkcgKyBSIGxvZzEwIiksIGFuZ2xlPTkwKSArCiAgdGhlbWVfYncoKQpgYGAKCgojLS0tLS0tLS0tLS0gdGltZSBzZXJpZXMgY29udmVyc2lvbiByYXRlIC0tLS0tLS0tLS0tLS0jCiMgZHluYW1pY3Mgc2ltdWxhdGlvbiBvZiBoaWdoIHBhcmFtZXRlciBjdWVzICh0aGVzZSBzZXJ2ZSBhcyByZWZlcmVuY2UgcG9pbnRzKQpgYGB7cn0KIyBiZXN0IGR1YWwgY3VlIGNvbWJvCmR1YWwuY3IgPC0gY2hhYmF1ZGlfc2lfY2xlYW4oCiAgcGFyYW1ldGVyc19jciA9IGMoNC40NDYxOTIwMzMsCTEwLjk3NTE4Mjc1LAkxLjM4NzYyODE3LAkyMy4zMDU5MjU0LAktMy40NTIwNTIzNzEsCS0xOC4wMDcwNjkyLAkzOS42NjYxNDIyNiwJLTMuNTQ1MTkzMTQxLAkxOC43ODM1MDc5OSksCiAgaW1tdW5pdHkgPSAidHN1a3VzaGkiLAogIHBhcmFtZXRlcnMgPSBwYXJhbWV0ZXJzX3RzdWt1c2hpLAogIHRpbWVfcmFuZ2UgPSBzZXEoMCwgMjAsIGJ5ID0gMWUtMyksCiAgY3VlX3JhbmdlID0gIHNlcSg2LCA3LCBieSA9IDEvNTAwKSwKICBjdWVfcmFuZ2VfYiA9IHNlcSgwLCBsb2cxMCg2KigxMF42KSksIGJ5ID0gKGxvZzEwKDYqKDEwXjYpKSkvNTAwKSwKICBjdWUgPSAiUiIsCiAgY3VlX2IgPSAiSSIsCiAgbG9nX2N1ZSA9ICJsb2cxMCIsCiAgbG9nX2N1ZV9iID0gImxvZzEwIiwKICBzb2x2ZXIgPSAidm9kZSIsCiAgZHluID0gVAopCgojIHdoZW4gdGltZSBpcyB1c2VkIGFzIGEgY3VlIChoaWdoIHBhcmFtZXRlcikKdGltZS5jciA8LSBjaGFiYXVkaV9zaV9jbGVhbl9oaWdoKAogIHBhcmFtZXRlcnNfY3IgPSBjKDkuMTU0MzE0LCAgLTcuNTcwODI5LCAtMjIuNTA2NjM4ICwgIDMuMzgyNDA1ICwtMTMuNDUzNTE5ICwtMTcuMDExNDg1ICAsIDMuNjc4MTgxLCAtMTIuODUxODk1ICwtMjYuMTE1MTU4KSwKICBpbW11bml0eSA9ICJ0c3VrdXNoaSIsCiAgcGFyYW1ldGVycyA9IHBhcmFtZXRlcnNfdHN1a3VzaGksCiAgdGltZV9yYW5nZSA9IHNlcSgwLCAyMCwgYnkgPSAxZS0zKSwKICBjdWVfcmFuZ2UgPSAgc2VxKDAsIDIwLCBieSA9IDFlLTMpLAogIGN1ZSA9ICJ0IiwKICBzb2x2ZXIgPSAidm9kZSIsCiAgZHluID0gVCkKCiMgd2hlbiBhc2V4dWFsIGlSQkMgaXMgdXNlZCBhcyBhIGN1ZSAoaGlnaCBmbGV4aWJpbGl0eSkKSV9oaWdoLmNyIDwtIGNoYWJhdWRpX3NpX2NsZWFuX2hpZ2goCiAgcGFyYW1ldGVyc19jciA9IGMoMS4yOTY2NzUsICAzLjU0NDAzNCAsIDQuOTA3NDg0LCAgMi4xNzQyNDksIC0zLjIzODMwOSAsLTUuMTgxNjE0ICwtMS42NDUwNzIgLCAxLjgzNDMwMiAsIDEuNTgxMDExKSwKICBpbW11bml0eSA9ICJ0c3VrdXNoaSIsCiAgcGFyYW1ldGVycyA9IHBhcmFtZXRlcnNfdHN1a3VzaGksCiAgdGltZV9yYW5nZSA9IHNlcSgwLCAyMCwgYnkgPSAxZS0zKSwKICBjdWVfcmFuZ2UgPSAgc2VxKDAsIGxvZzEwKDYqKDEwXjYpKSwgYnkgPSAobG9nMTAoNiooMTBeNikpKS81MDAwKSwKICBjdWUgPSAiSSIsCiAgbG9nX2N1ZSA9ICJsb2cxMCIsCiAgc29sdmVyID0gInZvZGUiLAogIGR5biA9IFQpCgojIHdoZW4gYXNleHVhbCBpUkJDIGlzIHVzZWQgYXMgYSBjdWUgKG5vcm1hbCBmbGV4aWJpbGl0eSkKSS5jciA8LSBjaGFiYXVkaV9zaV9jbGVhbigKICBwYXJhbWV0ZXJzX2NyID0gYyg1LjQ2MzU1OCwJMi4zODM5NDgsCS0xNy43NTcyODEsCTQuNTcxODM1KSwKICBpbW11bml0eSA9ICJ0c3VrdXNoaSIsCiAgcGFyYW1ldGVycyA9IHBhcmFtZXRlcnNfdHN1a3VzaGksCiAgdGltZV9yYW5nZSA9IHNlcSgwLCAyMCwgYnkgPSAxZS0zKSwKICBjdWVfcmFuZ2UgPSAgc2VxKDAsIGxvZzEwKDYqKDEwXjYpKSwgYnkgPSAobG9nMTAoNiooMTBeNikpKS81MDAwKSwKICBjdWUgPSAiSSIsCiAgbG9nX2N1ZSA9ICJsb2cxMCIsCiAgc29sdmVyID0gInZvZGUiLAogIGR5biA9IFQpCgojIHByb2Nlc3MgCklfaGlnaC5jcjIgPC0gSV9oaWdoLmNyICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gImNyIikgJT4lIG11dGF0ZShsYWJlbF9uZXcgPSAiSSBsb2cxMCAoZGY9OSkiKSAlPiUgc2VsZWN0KC12YXJpYWJsZSkKCkkuY3IyIDwtIEkuY3IgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiY3IiKSAlPiUgbXV0YXRlKGxhYmVsX25ldyA9ICJJIGxvZzEwIChkZj0zKSIpICU+JSBzZWxlY3QoLXZhcmlhYmxlKQoKdGltZV9oaWdoLmNyMiA8LSB0aW1lLmNyICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gImNyIikgJT4lIG11dGF0ZShsYWJlbF9uZXcgPSAiSWRlYWwgKGRmPTkpIikgJT4lIHNlbGVjdCgtdmFyaWFibGUpCgpkdWFsLmNyMiA8LSBkdWFsLmNyICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gImNyIikgJT4lIG11dGF0ZShsYWJlbF9uZXcgPSAiUiBsb2cxMCArIEkgbG9nMTAgKGRmPTkpIikgJT4lIHNlbGVjdCgtdmFyaWFibGUpCgojIGNvbWJpbmUKZHVhbF9jci5kZiA8LSByYmluZChJX2hpZ2guY3IyLCBJLmNyMiwgdGltZV9oaWdoLmNyMiwgZHVhbC5jcjIpCmBgYAoKIyBwbG90CmBgYHtyfQpkdWFsX2NyLnBsIDwtIGdncGxvdCgpICsKICBnZW9tX2xpbmUoZGF0YSA9IGR1YWxfY3IuZGYsIGFlcyhjb2xvciA9IGxhYmVsX25ldywgeCA9IHRpbWUsIHkgPSB2YWx1ZSksIHNpemUgPSAxKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZHVhbF9jci5kZiAlPiUgZmlsdGVyKHRpbWUlJTEgPT0gMCksIGFlcyhjb2xvciA9IGxhYmVsX25ldywgeCA9IHRpbWUsIHkgPSB2YWx1ZSwgc2hhcGUgPSBsYWJlbF9uZXcpLCBzaXplID0gMykgKwogIGxhYnMoeCA9ICJUaW1lIChkYXlzKSIsIHkgPSAiQ29udmVyc2lvbiByYXRlIiwgY29sb3IgPSAiQ3VlIiwgc2hhcGUgPSAiQ3VlIikgKwogIHhsaW0oMCwgMjApICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiI2ZjOGQ1OSIsIiNmZGNiNDQiLCJibGFjayIsICIjNDU3NWI0IikpICsKICB0aGVtZV9idygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpICsKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDIsIGJ5cm93ID0gVFJVRSkpCmBgYAoKIy0tLS0tLS0tLS0tLSByZWFjdGlvbiBub3JtIGhlYXRtYXAgb2YgUiBsb2cxMCArIEkgbG9nMTAgLS0tLS0tLS0tLS0tIwojIHByb2Nlc3MgZGF0YQpgYGB7cn0KIyBtYWtlIGhlYXRtYXAgZGYKUl9JLmhtIDwtIHBhcl90b19obV90ZShwYXIgPSBjKDQuNDQ2MTkyMDMzLAkxMC45NzUxODI3NSwJMS4zODc2MjgxNywJMjMuMzA1OTI1NCwJLTMuNDUyMDUyMzcxLAktMTguMDA3MDY5MiwJMzkuNjY2MTQyMjYsCS0zLjU0NTE5MzE0MSwJMTguNzgzNTA3OTkpLAogICAgICAgICAgICAgY3VlX3JhbmdlID0gc2VxKDYsCTcsIGxlbmd0aC5vdXQgPSA1MDApLAogICAgICAgICAgICAgY3VlX3JhbmdlX2IgPSBzZXEoMCwJNi43NzgxNTEyNSwgbGVuZ3RoLm91dCA9IDUwMCkpCgojIHByb2Nlc3MgZHluYW1pY3MKUl9JLmR5biA8LSBkdWFsLmNyICU+JSAKICB0aWR5cjo6cGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHZhcmlhYmxlLCB2YWx1ZXNfZnJvbSA9IHZhbHVlKSAlPiUgCiAgbXV0YXRlKGxvZ19SID0gbG9nMTAoUiksCiAgICAgICAgIGxvZ19JID0gbG9nMTAoSSkpCgojIGV4YW1pbmUgc2V4dWFsIGlSQkMgYXMgd2VsbApSX0lnLmR5biA8LSBkdWFsLmNyICU+JSAKICB0aWR5cjo6cGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHZhcmlhYmxlLCB2YWx1ZXNfZnJvbSA9IHZhbHVlKSAlPiUgCiAgbXV0YXRlKGxvZ19SID0gbG9nMTAoUiksCiAgICAgICAgIGxvZ19JZyA9IGxvZzEwKElnKSkKbWF4KFJfSWcuZHluJElnKSAKYGBgCgojIHBsb3QKYGBge3J9CmR1YWxfcm4ucGwgPC0gZ2dwbG90KCkgKwogIGdlb21fcmFzdGVyKGRhdGEgPSBSX0kuaG0sIGFlcyh4ID0gY3VlX3JhbmdlX2IsIHkgPSBjdWVfcmFuZ2UsIGZpbGwgPSBjcikpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfYygpICsKICBnZW9tX3BhdGgoZGF0YSA9IFJfSS5keW4sIGFlcyh4ID0gbG9nX0ksIHkgPSBsb2dfUiksIGNvbG9yID0gIndoaXRlIiwgYXJyb3cgPSBhcnJvdyhhbmdsZSA9IDMwLCBsZW5ndGggPSB1bml0KDAuMSwgImluY2hlcyIpKSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IFJfSS5keW4gJT4lIGZpbHRlcihyb3dfbnVtYmVyKCkgJSUgMTAwMCA9PSAxICYgdGltZSA8PSAyMCksIGFlcyh4ID0gbG9nX0ksIHkgPSBsb2dfUiksIGNvbG9yID0gIndoaXRlIikgKwogIHhsaW0oMC45OSptaW4oaGFibGFyOjpzKFJfSS5keW4kbG9nX0kpLCBuYS5ybSA9IFQpLCAxLjAxKiBtYXgoaGFibGFyOjpzKFJfSS5keW4kbG9nX0kpLCBuYS5ybSA9IFQpKSArCiAgeWxpbSgwLjk5Km1pbihoYWJsYXI6OnMoUl9JLmR5biRsb2dfUiksIG5hLnJtID0gVCksMS4wMSogbWF4KGhhYmxhcjo6cyhSX0kuZHluJGxvZ19SKSwgbmEucm0gPSBUKSkgKwogIGxhYnMoeSA9ICJSQkMgbG9nMTAiLCB4ID0gIkFzZXh1YWwgaVJCQyBsb2cxMCIsIGZpbGwgPSAiQ29udmVyc2lvbiByYXRlIikgKwogIHRoZW1lX2RhcmsoKQoKIyBqdXN0IHRlc3RpbmcgZm9yIHNleHVhbCBpUkJDIHZzIFJCQwpnZ3Bsb3QoKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBSX0lnLmR5biwgYWVzKHggPSBJZywgeSA9IGxvZ19SKSwgY29sb3IgPSAid2hpdGUiLCBhcnJvdyA9IGFycm93KGFuZ2xlID0gMzAsIGxlbmd0aCA9IHVuaXQoMC4xLCAiaW5jaGVzIikpKSArCiAgZ2VvbV9wb2ludChkYXRhID0gUl9JZy5keW4gJT4lIGZpbHRlcihyb3dfbnVtYmVyKCkgJSUgMTAwMCA9PSAxICYgdGltZSA8PSAyMCksIGFlcyh4ID0gSWcsIHkgPSBsb2dfUiksIGNvbG9yID0gIndoaXRlIikgKwogIHNjYWxlX3hfY29udGludW91cyh0cmFucyA9ICJsb2cxMCIpICsKICB4bGltKDAsIDIwMDAwMCkgKwogIGxhYnMoeSA9ICJSQkMgbG9nMTAiLCB4ID0gIlNleHVhbCBpUkJDIGxvZzEwIiwgZmlsbCA9ICJDb252ZXJzaW9uIHJhdGUiKSArCiAgdGhlbWVfZGFyaygpCmBgYAoKIyBzYXZlIGZpZ3VyZSBmb3IgcG9zdGVyCmBgYHtyfQpkdWFsX3JuLnBsMiA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9yYXN0ZXIoZGF0YSA9IFJfSS5obSwgYWVzKHggPSBjdWVfcmFuZ2VfYiwgeSA9IGN1ZV9yYW5nZSwgZmlsbCA9IGNyKSkgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKCkgKwogIGdlb21fcGF0aChkYXRhID0gUl9JLmR5biwgYWVzKHggPSBsb2dfSSwgeSA9IGxvZ19SKSwgY29sb3IgPSAid2hpdGUiLCBhcnJvdyA9IGFycm93KGFuZ2xlID0gMzAsIGxlbmd0aCA9IHVuaXQoMC4xLCAiaW5jaGVzIikpKSArCiAgZ2VvbV9wb2ludChkYXRhID0gUl9JLmR5biAlPiUgZmlsdGVyKHJvd19udW1iZXIoKSAlJSAxMDAwID09IDEgJiB0aW1lIDw9IDIwKSwgYWVzKHggPSBsb2dfSSwgeSA9IGxvZ19SKSwgY29sb3IgPSAid2hpdGUiKSArCiAgeGxpbSgwLjk5Km1pbihoYWJsYXI6OnMoUl9JLmR5biRsb2dfSSksIG5hLnJtID0gVCksIDEuMDEqIG1heChoYWJsYXI6OnMoUl9JLmR5biRsb2dfSSksIG5hLnJtID0gVCkpICsKICB5bGltKDAuOTkqbWluKGhhYmxhcjo6cyhSX0kuZHluJGxvZ19SKSwgbmEucm0gPSBUKSwxLjAxKiBtYXgoaGFibGFyOjpzKFJfSS5keW4kbG9nX1IpLCBuYS5ybSA9IFQpKSArCiAgbGFicyh5ID0gIlJCQyBsb2cxMCIsIHggPSAiQXNleHVhbCBpUkJDIGxvZzEwIiwgZmlsbCA9ICJDb252ZXJzaW9uIHJhdGUiKSArCiAgdGhlbWVfZGFyaygpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKSAKCmR1YWxfY3IucGwyIDwtIGdncGxvdCgpICsKICBnZW9tX2xpbmUoZGF0YSA9IGR1YWxfY3IuZGYsIGFlcyhjb2xvciA9IGxhYmVsX25ldywgeCA9IHRpbWUsIHkgPSB2YWx1ZSksIHNpemUgPSAxKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZHVhbF9jci5kZiAlPiUgZmlsdGVyKHRpbWUlJTEgPT0gMCksIGFlcyhjb2xvciA9IGxhYmVsX25ldywgeCA9IHRpbWUsIHkgPSB2YWx1ZSwgc2hhcGUgPSBsYWJlbF9uZXcpLCBzaXplID0gMikgKwogIGxhYnMoeCA9ICJUaW1lIChkYXlzKSIsIHkgPSAiQ29udmVyc2lvbiByYXRlIiwgY29sb3IgPSAiQ3VlIiwgc2hhcGUgPSAiQ3VlIikgKwogIHhsaW0oMCwgMjApICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiIzQ1NzViNCIsICIjOTFiZmRiIiwiI2ZjOGQ1OSIsIiNmZGNiNDQiKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0idG9wIikgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMiwgYnlyb3cgPSBUUlVFKSkKCmdnYXJyYW5nZShkdWFsX2NyLnBsMiwgZHVhbF9ybi5wbDIsIGFsaWduID0gImgiLCB3aWR0aHMgPSBjKDEuMjUsIDEpKQpnZ3NhdmUoaGVyZSgicG9zdGVyL2R1YWxfY3VlLnBuZyIpLCB3aWR0aCA9IDcsIGhlaWdodCA9IDQpCmBgYAoKCiMtLS0tLS0tLSBhc3NlbWJsZSBmaW5hbCBmaWd1cmUgLS0tLS0tLS0tLS0tLSMKYGBge3J9CiMgYXNzZW1ibGUgcGFuZWwgQiBhbmQgQwpkdWFsX3BsLkJDIDwtIGdnYXJyYW5nZShkdWFsX2NyLnBsLCBkdWFsX3JuLnBsLCBhbGlnbiA9ICJ2IiwgbmNvbCA9IDEsIGxhYmVscyA9IGMoIkIiLCAiQyIpKQoKIyBhc3NlbWJsZSBwYW5lbCBBCmdnYXJyYW5nZShkdWFsX3NpX2ZpdG5lc3MucGwsIGR1YWxfcGwuQkMsIG5jb2wgPSAyLCBsYWJlbHMgPSBjKCJBIiwgIiIpLCB3aWR0aHMgPSBjKDEsIDAuNzUpKQpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby9kdWFsX2N1ZS50aWZmIiksIHVuaXRzID0gInB4Iiwgd2lkdGggPSAyMjUwLCBoZWlnaHQgPSAxNDAwLCBzY2FsZSA9IDEuNSwgZHBpPTMwMCwgIGJnID0gIndoaXRlIikKYGBgCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIyBnZXQgZHVhbCBjdWUgZGlzZWFzZSBtYXAgKHNpbXVsYXRlZCkKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwpJIGFtIGdvaW5nIHRvIHRha2UgdGhlIG9wdGltYWwgZHluYW1pYyAoUiBsb2cxMCArIEkgbG9nMTApIGFuZCBwbG90IGFsbCBwb3NzaWJsZSBkaXNlYXNlIGN1cnZlcyBhbmQgc2VlIGlmIGFueSBmb2xsb3cgdGhlIGh5c3RlcmVzaXMgY3VydmUuIFNlZSBiZWxvdyBmb3IgcmVhbCBsaWZlIGRpc2Vhc2UgY3VydmUuCmBgYHtyfQojIGdldCBsaXN0IG9mIGludGVyZXN0ZWQgdmFyaWFibGVzIGZvciBwbG90dGluZy4gZHJvcCBjciwgZml0bmVzcywgYW5kIGRlYXRoIHByb2JhYmlsaXR5LCBpbW11bml0eQpkdWFsX3Zhci5scyA8LSB1bmlxdWUoZHVhbC5jciR2YXJpYWJsZSlbIXVuaXF1ZShkdWFsLmNyJHZhcmlhYmxlKSAlaW4lIGMoInRhdSIsICJ0YXVfY3VtIiwgImNyIiwgImNyX3QiLCAiSUQiLCAiTiIsICJXIildCgojIGNyZWF0ZSBhbGwgcG9zc2libGUgdmFyaWFibGUgY29tYmluYXRpb25zLiAyOCB2YXJpYWJsZSBjb21iaW5hdGlvbiAoOCo4IHdpdGggOCBzYW1lIHJlZHVuZGFudCBhbmQgaGFsZiBvZiB0aGF0KSBpcyBleHBlY3RlZApkdWFsX3Zhci5jb21iIDwtIHRpZHlyOjpleHBhbmRfZ3JpZCh4ID0gZHVhbF92YXIubHMsCiAgICAgICAgICAgICAgICAgICAgICB5ID0gZHVhbF92YXIubHMpICU+JSAKICBmaWx0ZXIoeCAhPSB5KSAlPiUgCiAgbXV0YXRlKHRtcCA9IHBhc3RlMChwbWluKHgsIHkpLCBwbWF4KHgsIHkpKSkgJT4lICMgZWxpbWluYXRlIHNhbWUgdmFyaWFibGUgYnV0IGRpZmZlcmVudCBvcmRlcgogIHNsaWNlX2hlYWQobiA9IDEsIGJ5ID0gdG1wKSAlPiUgCiAgc2VsZWN0KC10bXApCgplel9sYWJlbAoKIyBmaWx0ZXIgb3V0IGludGVybWVkaWF0ZSBkYXRhIHBvaW50cyBpbiBkeW5hbWljIHNvIHdlIGNvdWxkIGhhdmUgZmFzdGVyIHBsb3R0aW5nLiBBbHNvIG1ha2Ugd2lkZXIgZm9yIHBsb3R0aW5nCmR1YWxfdmFyLmNvbWIKCmR1YWxfY3IuZiA8LSBkdWFsLmNyICU+JSAKICBncm91cF9ieSh2YXJpYWJsZSkgJT4lIAogIG11dGF0ZShsYWJlbCA9IAogICAgICAgICAgIGNhc2Vfd2hlbigKICAgICAgICAgICAgIHZhcmlhYmxlID09ICJSIiB+ICJSQkMiLAogICAgICAgICAgICAgdmFyaWEKICAgICAgICAgICApKQogIGFycmFuZ2UodGltZSwgLmJ5X2dyb3VwID0gVCkgJT4lIAogIGZpbHRlcihyb3dfbnVtYmVyKCkgJSUgMTAwID09IDEpICU+JSAKICB0aWR5cjo6cGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHZhcmlhYmxlLCBpZF9jb2xzID0gYyh0aW1lKSkKCiMgbWFrZSBwYXRoIHBsb3QKcHVycnI6Om1hcDIoLnggPSBkdWFsX3Zhci5jb21iJHgsIAogICAgIC55ID0gZHVhbF92YXIuY29tYiR5LAogICAgICB+e2dncGxvdCgpICsKICAgICAgICAgIGdlb21fcGF0aChkYXRhID0gZHVhbF9jci5mLCBhZXNfc3RyaW5nKHggPSAueSwgeSA9IC54LCBjb2xvciA9ICJjciIpLAogICAgICAgICAgICAgICAgICAgIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdChjKHJlcCgwLCBucm93KGR1YWxfY3IuZikgLSAyKSwgMC4yNSksICJpbmNoZXMiKSksCiAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEuNSkgKwogICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gZHVhbF9jci5mICU+JSBmaWx0ZXIocm93X251bWJlcigpICUlIDEwID09MSksIAogICAgICAgICAgICAgICAgICAgICBhZXNfc3RyaW5nKHggPSAueSwgeSA9IC54LCBjb2xvciA9ICJjciIpLCBzaXplID0gMykgKwogICAgICAgICAgc2NhbGVfY29sb3JfdmlyaWRpc19jKCkgKwogICAgICAgICAgdGhlbWVfYncoKQogICAgICAgIH0KICAgICAgICAgICkKCiAKCmBgYAoKCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIyByZWFsIGxpZmUgZGlzZWFzZSBjdXJ2ZQojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMgZXhlY3V0ZSBjb2RlIGZyb20gcmVwb3J0IDEwIHRvIGdldCBmaW5hbCBkYXRhc2V0ClRoZSBmb2xsb3dpbmcgZ3JhcGhzIHdpbGwgYmUgbWFkZToKLSBSIHZzIGlSQkMKLSBSIGxvZzEwIHZzIGlSQkMKLSBSIHZzIGlSQkMgbG9nMTAKLSBSIGxvZzEwIHZzIGlSQkMgbG9nMTAKCi0gRyB2cyBpUkJDCi0gRyBsb2cxMCB2cyBpUkJDCi0gRyB2cyBpUkJDIGxvZzEwCi0gRyBsb2cxMCB2cyBpUkJDIGxvZzEwCgotIFIgdnMgRwotIFIgbG9nMTAgdnMgRwotIFIgdnMgRyBsb2cxMAotIFIgbG9nMTAgdnMgRyBsb2cxMAoKUiBvbiB5LWF4aXMKYGBge3J9CnJfaS5kYyA8LSBnZ3Bsb3QoZXhwX3NzLmRmKSArCiAgZ2VvbV9wb2ludChhZXMoeSA9IFJCQywgeCA9IGFzZXgpKSArCiAgZ2VvbV9wYXRoKGFlcyh5ID0gUkJDLCB4ID0gYXNleCwgY29sb3VyID0gZGF5LCBncm91cCA9IGlkKSwgYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgdGhlbWVfYncoKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYyhsaW1pdHMgPSBjKDMsIDIxKSkgKwogIGxhYnMoeCA9ICJpUkJDIHBlciDCtUwiLCB5ID0gIlJCQyBwZXIgwrVMIiwgY29sb3IgPSAiRGF5c1xucG9zdC1pbmZlY3Rpb24iKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSkpCgpybG9nX2kuZGMgPC0gZ2dwbG90KGV4cF9zcy5kZikgKwogIGdlb21fcG9pbnQoYWVzKHkgPSBsb2cxMChSQkMpLCB4ID0gYXNleCkpICsKICBnZW9tX3BhdGgoYWVzKHkgPSBsb2cxMChSQkMpLCB4ID0gYXNleCwgY29sb3VyID0gZGF5LCBncm91cCA9IGlkKSwgYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgdGhlbWVfYncoKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYyhsaW1pdHMgPSBjKDMsIDIxKSkgKwogIGxhYnMoeCA9ICJpUkJDIHBlciDCtUwiLCB5ID0gImxvZzEwKFJCQykgcGVyIMK1TCIsIGNvbG9yID0gIkRheXNcbnBvc3QtaW5mZWN0aW9uIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFRSVUUpKQoKcl9pbG9nLmRjIDwtZ2dwbG90KGV4cF9zcy5kZikgKwogIGdlb21fcG9pbnQoYWVzKHkgPSBSQkMsIHggPSBsb2cxMChhc2V4KSkpICsKICBnZW9tX3BhdGgoYWVzKHkgPSBSQkMsIHggPSBsb2cxMChhc2V4KSwgY29sb3VyID0gZGF5LCBncm91cCA9IGlkKSwgYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgdGhlbWVfYncoKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYyhsaW1pdHMgPSBjKDMsIDIxKSkgKwogIGxhYnMoeCA9ICJsb2cxMChpUkJDKSBwZXIgwrVMIiwgeSA9ICJSQkMgcGVyIMK1TCIsIGNvbG9yID0gIkRheXNcbnBvc3QtaW5mZWN0aW9uIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFRSVUUpKQoKcmxvZ19pbG9nLmRjIDwtIGdncGxvdChleHBfc3MuZGYpICsKICBnZW9tX3BvaW50KGFlcyh5ID0gbG9nMTAoUkJDKSwgeCA9IGxvZzEwKGFzZXgpKSkgKwogIGdlb21fcGF0aChhZXMoeSA9IGxvZzEwKFJCQyksIHggPSBsb2cxMChhc2V4KSwgY29sb3VyID0gZGF5LCBncm91cCA9IGlkKSwgYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgdGhlbWVfYncoKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYyhsaW1pdHMgPSBjKDMsIDIxKSkgKwogIGxhYnMoeCA9ICJsb2cxMChpUkJDKSBwZXIgwrVMIiwgeSA9ICJsb2cxMChSQkMpIHBlciDCtUwiLCBjb2xvciA9ICJEYXlzXG5wb3N0LWluZmVjdGlvbiIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUUlVFKSkKYGBgCgpHIG9uIHktYXhpcwpgYGB7cn0KZ19pLmRjIDwtIGdncGxvdChleHBfc3MuZGYpICsKICBnZW9tX3BvaW50KGFlcyh5ID0gZ2FtLCB4ID0gYXNleCkpICsKICBnZW9tX3BhdGgoYWVzKHkgPSBnYW0sIHggPSBhc2V4LCBjb2xvdXIgPSBkYXksIGdyb3VwID0gaWQpLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKGxpbWl0cyA9IGMoMywgMjEpKSArCiAgbGFicyh4ID0gImlSQkMgcGVyIMK1TCIsIHkgPSAiR2FtZXRvY3l0ZSBwZXIgwrVMIiwgY29sb3IgPSAiRGF5c1xucG9zdC1pbmZlY3Rpb24iKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSkpCgpnbG9nX2kuZGMgPC0gZ2dwbG90KGV4cF9zcy5kZikgKwogIGdlb21fcG9pbnQoYWVzKHkgPSBsb2cxMChnYW0pLCB4ID0gYXNleCkpICsKICBnZW9tX3BhdGgoYWVzKHkgPSBsb2cxMChnYW0pLCB4ID0gYXNleCwgY29sb3VyID0gZGF5LCBncm91cCA9IGlkKSwgYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgdGhlbWVfYncoKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYyhsaW1pdHMgPSBjKDMsIDIxKSkgKwogIGxhYnMoeCA9ICJpUkJDIHBlciDCtUwiLCB5ID0gImxvZzEwKEdhbWV0b2N5dGUpIHBlciDCtUwiLCBjb2xvciA9ICJEYXlzXG5wb3N0LWluZmVjdGlvbiIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUUlVFKSkKCmdfaWxvZy5kYyA8LSBnZ3Bsb3QoZXhwX3NzLmRmKSArCiAgZ2VvbV9wb2ludChhZXMoeSA9IGdhbSwgeCA9IGxvZzEwKGFzZXgpKSkgKwogIGdlb21fcGF0aChhZXMoeSA9IGdhbSwgeCA9IGxvZzEwKGFzZXgpLCBjb2xvdXIgPSBkYXksIGdyb3VwID0gaWQpLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKGxpbWl0cyA9IGMoMywgMjEpKSArCiAgbGFicyh4ID0gImxvZzEwKGlSQkMpIHBlciDCtUwiLCB5ID0gIkdhbWV0b2N5dGUgcGVyIMK1TCIsIGNvbG9yID0gIkRheXNcbnBvc3QtaW5mZWN0aW9uIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFRSVUUpKQoKZ2xvZ19pbG9nLmRjIDwtIGdncGxvdChleHBfc3MuZGYpICsKICBnZW9tX3BvaW50KGFlcyh5ID0gbG9nMTAoZ2FtKSwgeCA9IGxvZzEwKGFzZXgpKSkgKwogIGdlb21fcGF0aChhZXMoeSA9IGxvZzEwKGdhbSksIHggPSBsb2cxMChhc2V4KSwgY29sb3VyID0gZGF5LCBncm91cCA9IGlkKSwgYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgdGhlbWVfYncoKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYyhsaW1pdHMgPSBjKDMsIDIxKSkgKwogIGxhYnMoeCA9ICJsb2cxMChpUkJDKSBwZXIgwrVMIiwgeSA9ICJsb2cxMChHYW1ldG9jeXRlKSBwZXIgwrVMIiwgY29sb3IgPSAiRGF5c1xucG9zdC1pbmZlY3Rpb24iKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSkpCmBgYAoKUiB2cyBHCmBgYHtyfQpyX2cuZGMgPC0gZ2dwbG90KGV4cF9zcy5kZikgKwogIGdlb21fcG9pbnQoYWVzKHkgPSBSQkMsIHggPSBnYW0pKSArCiAgZ2VvbV9wYXRoKGFlcyh5ID0gUkJDLCB4ID0gZ2FtLCBjb2xvdXIgPSBkYXksIGdyb3VwID0gaWQpLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKGxpbWl0cyA9IGMoMywgMjEpKSArCiAgbGFicyh4ID0gIkdhbWV0b2N5dGUgcGVyIMK1TCIsIHkgPSAiUkJDIHBlciDCtUwiLCBjb2xvciA9ICJEYXlzXG5wb3N0LWluZmVjdGlvbiIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUUlVFKSkKCnJsb2dfZy5kYyA8LSBnZ3Bsb3QoZXhwX3NzLmRmKSArCiAgZ2VvbV9wb2ludChhZXMoeSA9IGxvZzEwKFJCQyksIHggPSBnYW0pKSArCiAgZ2VvbV9wYXRoKGFlcyh5ID0gbG9nMTAoUkJDKSwgeCA9IGdhbSwgY29sb3VyID0gZGF5LCBncm91cCA9IGlkKSwgYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgdGhlbWVfYncoKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYyhsaW1pdHMgPSBjKDMsIDIxKSkgKwogIGxhYnMoeCA9ICJHYW1ldG9jeXRlIHBlciDCtUwiLCB5ID0gImxvZzEwKFJCQyBwZXIgwrVMKSIsIGNvbG9yID0gIkRheXNcbnBvc3QtaW5mZWN0aW9uIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFRSVUUpKQoKcl9nbG9nLmRjIDwtIGdncGxvdChleHBfc3MuZGYpICsKICBnZW9tX3BvaW50KGFlcyh5ID0gUkJDLCB4ID0gbG9nMTAoZ2FtKSkpICsKICBnZW9tX3BhdGgoYWVzKHkgPSBSQkMsIHggPSBsb2cxMChnYW0pLCBjb2xvdXIgPSBkYXksIGdyb3VwID0gaWQpLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKGxpbWl0cyA9IGMoMywgMjEpKSArCiAgbGFicyh4ID0gImxvZzEwKEdhbWV0b2N5dGUpIHBlciDCtUwiLCB5ID0gIlJCQyBwZXIgwrVMIiwgY29sb3IgPSAiRGF5c1xucG9zdC1pbmZlY3Rpb24iKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSkpCgpybG9nX2dsb2cuZGMgPC0gZ2dwbG90KGV4cF9zcy5kZikgKwogIGdlb21fcG9pbnQoYWVzKHkgPSBsb2cxMChSQkMpLCB4ID0gbG9nMTAoZ2FtKSkpICsKICBnZW9tX3BhdGgoYWVzKHkgPSBsb2cxMChSQkMpLCB4ID0gbG9nMTAoZ2FtKSwgY29sb3VyID0gZGF5LCBncm91cCA9IGlkKSwgYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgdGhlbWVfYncoKSArIAogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYyhsaW1pdHMgPSBjKDMsIDIxKSkgKwogIGxhYnMoeCA9ICJsb2cxMChHYW1ldG9jeXRlKSBwZXIgwrVMIiwgeSA9ICJsb2cxMChSQkMpIHBlciDCtUwiLCBjb2xvciA9ICJEYXlzXG5wb3N0LWluZmVjdGlvbiIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUUlVFKSkKYGBgCgojIHBsb3QgdG9nZXRoZXIKYGBge3J9CmdnYXJyYW5nZShyX2kuZGMsIHJsb2dfaS5kYywgcl9pbG9nLmRjLCBybG9nX2lsb2cuZGMsCiAgICAgICAgICBnX2kuZGMsIGdsb2dfaS5kYywgZ19pbG9nLmRjLCBnbG9nX2lsb2cuZGMsCiAgICAgICAgICByX2cuZGMsIHJsb2dfZy5kYywgcl9nbG9nLmRjLCBybG9nX2dsb2cuZGMsIAogICAgICAgICAgbmNvbCA9IDQsIG5yb3cgPSAzLCBhbGlnbiA9ICJodiIsIGNvbW1vbi5sZWdlbmQgPSBUKQpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby9leHBfZGlzZWFzZS1jdXJ2ZS50aWZmIiksIHVuaXRzID0gInB4Iiwgd2lkdGggPSAyMjUwLCBoZWlnaHQgPSAxNTAwLCBzY2FsZSA9IDIsIGRwaT0zMDAsICBiZyA9ICJ3aGl0ZSIpCmBgYAoKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMgc3RhdGljIGNvbXBldGl0aW9uCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwojLS0tLS0tLSBoZWF0IG1hcCAtLS0tLS0tLS0tLS0tLS0jCiMgY2FsY3VsYXRlIGZpdG5lc3MgZGlmZmVyZW5jZSBmb3IgMjAgZGF5cwpgYGB7cn0KIyBnZXQgZHluYW1pY3MKc3RhdGljLmxzIDwtIGxpc3QuZmlsZXMocGF0aCA9IGhlcmUoImRhdGEvY2lfc3RhdGljLyIpLCBwYXR0ZXJuID0gIioucGFycXVldCIsIGZ1bGwubmFtZXMgPSBUKQpzdGF0aWMubHMgPC0gbGFwcGx5KHN0YXRpYy5scywgcmVhZF9wYXJxdWV0KQoKIyBnZXQgZml0bmVzcyBhdCBkYXkgMjAgKG9wdGltaXplZCBmb3IgMjAgZGF5cykKc3RhdGljX2ZpdG5lc3MubHMgPC0gbWNsYXBwbHkoc3RhdGljLmxzLCBmdW5jdGlvbih4KXsKICB4ICU+JSBmaWx0ZXIodGltZSA9PSAyMCAmIHZhcmlhYmxlICVpbiUgYygidGF1X2N1bTEiLCAidGF1X2N1bTIiKSkKfSkKc3RhdGljX2ZpdG5lc3MuZGYgPC0gZG8uY2FsbChyYmluZCwgc3RhdGljX2ZpdG5lc3MubHMpCgpzdGF0aWNfZml0bmVzcy5kZiA8LSB0aWR5cjo6cGl2b3Rfd2lkZXIoc3RhdGljX2ZpdG5lc3MuZGYsIG5hbWVzX2Zyb20gPSAidmFyaWFibGUiLCBpZF9jb2xzID0gYygiaWRfMSIsICJpZF8yIikpICU+JSAKICBncm91cF9ieShpZF8xLCBpZF8yKSAlPiUgCiAgbXV0YXRlKGZpdG5lc3NfZGlmZmVyZW5jZSA9IHRhdV9jdW0xLXRhdV9jdW0yKQp3cml0ZS5jc3Yoc3RhdGljX2ZpdG5lc3MuZGYsIGhlcmUoImRhdGEvY2lfc3RhdGljLmNzdiIpKQpgYGAKCiMgaW1wb3J0IGFuZCBwcm9jZXNzIGRhdGEKYGBge3J9CiMgaW1wb3J0IGluIGRhdGFzZXQKc3RhdGljLmRmIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvY2lfc3RhdGljLmNzdiIpKQplel9sYWJlbCA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2V6X2xhYmVsLmNzdiIpKQoKIyBqb2luIHdpdGggbGFiZWxsaW5nCnN0YXRpYy5kZjIgPC0gc3RhdGljLmRmICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGV6X2xhYmVsLCBpZF9jaSwgbGFiZWxfY2lfMSA9IGxhYmVsX2NpKSwgYnkgPSBjKCJpZF8xIiA9ICJpZF9jaSIpKSAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChlel9sYWJlbCwgaWRfY2ksIGxhYmVsX2NpXzIgPSBsYWJlbF9jaSksIGJ5ID0gYygiaWRfMiIgPSAiaWRfY2kiKSkgJT4lIAogIHNlbGVjdChsYWJlbF9jaV8xLCBsYWJlbF9jaV8yLCBmaXRuZXNzX2RpZmZlcmVuY2UpICU+JSAKICBtdXRhdGUobGFiZWxfY2lfMSA9IGdzdWIoImxvZyIsICJsb2cxMCIsIGxhYmVsX2NpXzEpLAogICAgICAgICBsYWJlbF9jaV8yID0gZ3N1YigibG9nIiwgImxvZzEwIiwgbGFiZWxfY2lfMikpCgojIGdldCByZXZlcnNlIG9yZGVyLCB3aGljaCBpcyBzaW1wbHkgaW52b3ZsZXMgc3dpdGNoaW5nIHRoZSBjdWVzIGFyb3VuZCB0aGUgbXVsdGlwbHlpbmcgdGhlIGZpdG5lc3MgYnkgbmVnYXRpdmUgMQpzdGF0aWMuZGYzIDwtIHN0YXRpYy5kZjIKbmFtZXMoc3RhdGljLmRmMykgPC0gYygibGFiZWxfY2lfMiIsICJsYWJlbF9jaV8xIiwgImZpdG5lc3NfZGlmZmVyZW5jZSIpCnN0YXRpYy5kZjMkZml0bmVzc19kaWZmZXJlbmNlIDwtIHN0YXRpYy5kZjIkZml0bmVzc19kaWZmZXJlbmNlICogLTEKCiMgam9pbgpzdGF0aWMuZGY0IDwtIHJiaW5kKHN0YXRpYy5kZjIsIHN0YXRpYy5kZjMpCgojIGdldCBtZWFuCnN0YXRpYy5tZWFuIDwtIHN0YXRpYy5kZjQgJT4lIAogIGRpc3RpbmN0KGxhYmVsX2NpXzEsIGxhYmVsX2NpXzIsIC5rZWVwX2FsbCA9IFQpICU+JSAKICBncm91cF9ieShsYWJlbF9jaV8xKSAlPiUgCiAgc3VtbWFyaXplKG1lYW5fZml0bmVzcyA9IG1lYW4oZml0bmVzc19kaWZmZXJlbmNlLCBuYS5ybSA9IFQpKQogIAoKIyBqb2luIHN0YXRpYy5kZjQgd2l0aCBtZWFuIGZvciBvcmRlciBzb3J0aW5nCnN0YXRpYy5kZjUgPC0gc3RhdGljLmRmNCAlPiUgCiAgbGVmdF9qb2luKHN0YXRpYy5tZWFuLCBieSA9ICJsYWJlbF9jaV8xIikgJT4lIAogIG11dGF0ZShsYWJlbF9jaV8xID0gZmN0X3Jlb3JkZXIobGFiZWxfY2lfMSwgbWVhbl9maXRuZXNzKSwKICAgICAgICAgbGFiZWxfY2lfMiA9IGZjdF9yZWxldmVsKGxhYmVsX2NpXzIsIGxldmVscyhzdGF0aWMuZGY1JGxhYmVsX2NpXzEpKSkKYGBgCgojIHBsb3QKYGBge3J9CiMgaGVhdG1hcApzdGF0aWMucGwxIDwtIGdncGxvdChkYXRhID0gc3RhdGljLmRmNSwgYWVzKHggPSBsYWJlbF9jaV8yLCB5ID0gbGFiZWxfY2lfMSwgbWVhbl9maXRuZXNzLCBmaWxsID0gZml0bmVzc19kaWZmZXJlbmNlKSkrCiAgZ2VvbV90aWxlKGNvbG9yID0gImJsYWNrIikgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKGxvdyA9ICIjZmM4ZDU5IiwgaGlnaCA9ICIjNDU3NWI0IiwgbWlkID0gIndoaXRlIiwgCiAgIG1pZHBvaW50ID0gMCwgc3BhY2UgPSAiTGFiIiwgbGltID0gYygtMC45NSwgMC45NSksIG5hbWU9IkZpdG5lc3NcbmRpZmZlcmVuY2UiKSArCiAgdGhlbWVfbWluaW1hbCgpICsgIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJsZWZ0IiwKICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCB2anVzdCA9IDEsIGhqdXN0ID0gMSksCiAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksCiAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksCiAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICBwbG90Lm1hcmdpbj1tYXJnaW4ociA9IC0xLCBsID0gLTEsIHVuaXQgPSAicHQiKSkgKyAKICBsYWJzKHggPSAiU3RyYWluIDIgY3VlIiwgeSA9ICJTdHJhaW4gMSBjdWUiKSArCiAgY29vcmRfZml4ZWQoKQoKIyBtZWFuIApzdGF0aWMucGwyIDwtIGdncGxvdCgpICsKICBnZW9tX2JhcihkYXRhID0gIHN0YXRpYy5tZWFuLCBhZXMoeSA9IGZjdF9yZW9yZGVyKGxhYmVsX2NpXzEsIG1lYW5fZml0bmVzcyksIHggPSBtZWFuX2ZpdG5lc3MpLCBzdGF0ID0gImlkZW50aXR5IikgKwogIGxhYnMoeSA9ICIiLCB4ID0gIk1lYW4gZml0bmVzc1xuZGlmZmVyZW5jZSIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwbG90Lm1hcmdpbiA9IG1hcmdpbihsID0gMCksCiAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLAogICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aWNrcy55PWVsZW1lbnRfYmxhbmsoKSkKCmdnYXJyYW5nZShzdGF0aWMucGwxLCBzdGF0aWMucGwyLCBhbGlnbiA9ICJodiIsIHdpZHRocyA9IGMoMSwgMC4yKSkKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vc3RhdGljX2NvbXBldGl0aW9uX2EudGlmZiIpLCB1bml0cyA9ICJweCIsIHdpZHRoID0gMjI1MCwgaGVpZ2h0ID0gMTUwMCwgc2NhbGUgPSAxLjIsIGRwaT0zMDAsICBiZyA9ICJ3aGl0ZSIpCmBgYAoKIy0tLS0tLSBlZmZlY3QgY3VlIHBlcmNlcHRpb24gLS0tLS0tLSMKIyMgbG9nZ2luZwpgYGB7cn0KIyBnZXQgbm9uLWxvZ2dlZCBwYWlyaW5ncwpzdGF0aWNfbm9sb2cgPC0gc3RhdGljLmRmMiAlPiUgCiAgbXV0YXRlKGN1ZV8xID0gdHJpbXdzKGdzdWIoIlxcIC4qIiwgIiIsIGxhYmVsX2NpXzEpKSwKICAgICAgICAgbG9nXzEgPSBjYXNlX3doZW4oCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIikgfiAibG9nIiwKICAgICAgICAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJsb2ciLCBuZWdhdGUgPSBUKSB+ICJub25lIikpICU+JSAKICBmaWx0ZXIobG9nXzEgPT0gIm5vbmUiKQoKc3RhdGljX2xvZyA8LSBzdGF0aWMuZGYyICU+JSAKICBtdXRhdGUoY3VlXzEgPSB0cmltd3MoZ3N1YigiXFwgLioiLCAiIiwgbGFiZWxfY2lfMSkpLAogICAgICAgICBsb2dfMSA9IGNhc2Vfd2hlbigKICAgICAgICAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJsb2ciKSB+ICJsb2ciLAogICAgICAgICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgImxvZyIsIG5lZ2F0ZSA9IFQpIH4gIm5vbmUiKSkgJT4lIAogIGZpbHRlcihsb2dfMSA9PSAibG9nIikKCnN0YXRpY19sb2cuZGYgPC0gbGVmdF9qb2luKAogIHNlbGVjdChzdGF0aWNfbm9sb2csIGN1ZV8xLCBsYWJlbF9jaV8yLCBsb2dfMSwgTm9uZSA9IGZpdG5lc3NfZGlmZmVyZW5jZSksCiAgc2VsZWN0KHN0YXRpY19sb2csIGN1ZV8xLCBsYWJlbF9jaV8yLCBsb2dfMSwgTG9nID0gZml0bmVzc19kaWZmZXJlbmNlKSwKICBieSA9IGMoImN1ZV8xIiwgImxhYmVsX2NpXzIiKSkgJT4lIAogIGZpbHRlcighaXMubmEoTm9uZSkgJiAhaXMubmEoTG9nKSkgJT4lIAogIG11dGF0ZShjbGFzc2lmaWNhdGlvbiA9IGlmZWxzZShMb2cgPiBOb25lLCAiTG9nZ2VkIGJldHRlciIsICJOb3QgbG9nZ2VkIGJldHRlciIpKQpgYGAKCiMgY29tYmluZWQKYGBge3J9CnN0YXRpY19ub2NvbWIgPC0gc3RhdGljLmRmMiAlPiUgCiAgbXV0YXRlKGN1ZV8xID0gaWZlbHNlKAogICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAic3VtIiksICJJK0lnIiwKICAgIHRyaW13cyhnc3ViKCIrMS4qfFxcIGxvZyIsICIiLCBsYWJlbF9jaV8xKSkKICApLAogIGxvZ18xID0gY2FzZV93aGVuKAogICAgICAgICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgImxvZyIpIH4gImxvZyIsCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIiwgbmVnYXRlID0gVCkgfiAibm9uZSIpLAogICAgY29tYl8xID0gY2FzZV93aGVuKAogICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAiMSt8c3VtIikgfiAiY29tYiIsCiAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICIxK3xzdW0iLCBuZWdhdGUgPSBUKSB+ICJub25lIiAKICApKSAlPiUgCiAgZmlsdGVyKGNvbWJfMSA9PSAibm9uZSIpCgpzdGF0aWNfY29tYiA8LSBzdGF0aWMuZGYyICU+JSAKICBtdXRhdGUoY3VlXzEgPSBpZmVsc2UoCiAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJzdW0iKSwgIkkrSWciLAogICAgdHJpbXdzKGdzdWIoIisxLip8XFwgbG9nIiwgIiIsIGxhYmVsX2NpXzEpKQogICksCiAgbG9nXzEgPSBjYXNlX3doZW4oCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIikgfiAibG9nIiwKICAgICAgICAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJsb2ciLCBuZWdhdGUgPSBUKSB+ICJub25lIiksCiAgICBjb21iXzEgPSBjYXNlX3doZW4oCiAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICIxK3xzdW0iKSB+ICJjb21iIiwKICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgIjErfHN1bSIsIG5lZ2F0ZSA9IFQpIH4gIm5vbmUiIAogICkpICU+JSAKICBmaWx0ZXIoY29tYl8xID09ICJjb21iIikKICAKc3RhdGljX2NvbWIuZGYgPC0gbGVmdF9qb2luKAogIHNlbGVjdChzdGF0aWNfbm9jb21iLCBjdWVfMSwgbGFiZWxfY2lfMiwgbG9nXzEsIFNlbGYgPSBmaXRuZXNzX2RpZmZlcmVuY2UpLAogIHNlbGVjdChzdGF0aWNfY29tYiwgY3VlXzEsIGxhYmVsX2NpXzIsIGxvZ18xLCBUb3RhbCA9IGZpdG5lc3NfZGlmZmVyZW5jZSksCiAgYnkgPSBjKCJjdWVfMSIsICJsb2dfMSIsICJsYWJlbF9jaV8yIikpICU+JSAKICBmaWx0ZXIoIWlzLm5hKFRvdGFsKSAmICFpcy5uYShTZWxmKSkgJT4lIAogIG11dGF0ZShjbGFzc2lmaWNhdGlvbiA9IGlmZWxzZShUb3RhbCA+IFNlbGYsICJUb3RhbCBiZXR0ZXIiLCAiU2VsZiBiZXR0ZXIiKSkKYGBgCgojIHBsb3QKYGBge3J9CnN0YXRpY19sb2cucGwgPC0gZ2dwYWlyZWQoc3RhdGljX2xvZy5kZiwgY29uZDEgPSAiTm9uZSIsIGNvbmQyID0gIkxvZyIsIGxpbmUuY29sb3IgPSAiY2xhc3NpZmljYXRpb24iLCBhbHBoYSA9IDAuNSkgKwogIGxhYnMoeCA9ICJDdWUgcGVyY2VwdGlvbiIsIHkgPSAiRml0bmVzcyBkaWZmZXJlbmNlIiwgY29sb3IgPSAiRWZmZWN0IikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJOb3QgbG9nZ2VkIGJldHRlciIgPSAiI2ZjOGQ1OSIsICJMb2dnZWQgYmV0dGVyIiA9ICIjNDU3NWI0IikpICsKICBzdGF0X2NvbXBhcmVfbWVhbnMocGFpcmVkID0gVFJVRSwgaGp1c3QgPSAtMC4xKQoKc3RhdGljX2NvbWIucGwgPC0gZ2dwYWlyZWQoc3RhdGljX2NvbWIuZGYsIGNvbmQxID0gIlRvdGFsIiwgY29uZDIgPSAiU2VsZiIsIGxpbmUuY29sb3IgPSAiY2xhc3NpZmljYXRpb24iLCBhbHBoYSA9IDAuNSkgKwogIGxhYnMoeCA9ICJDdWUgcGVyY2VwdGlvbiIsIHkgPSAiRml0bmVzcyBkaWZmZXJlbmNlIiwgY29sb3IgPSAiRWZmZWN0IikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJUb3RhbCBiZXR0ZXIiID0gIiNmYzhkNTkiLCAiU2VsZiBiZXR0ZXIiID0gIiM0NTc1YjQiKSkgKwogIHN0YXRfY29tcGFyZV9tZWFucyhwYWlyZWQgPSBUUlVFLCBoanVzdCA9IC0wLjIpCgpnZ2FycmFuZ2Uoc3RhdGljX2xvZy5wbCwgc3RhdGljX2NvbWIucGwsIG5jb2wgPSAxLCBucm93ID0gMiwgYWxpZ24gPSAidiIpCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3Bsb3MtYmlvL3N0YXRpY19jb21wZXRpdGlvbl9iLnRpZmYiKSwgdW5pdHMgPSAicHgiLCB3aWR0aCA9IDEwMDAsIGhlaWdodCA9IDIwMDAsIHNjYWxlID0gMS4yLCBkcGk9MzAwLCAgYmcgPSAid2hpdGUiKQpgYGAKCgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIyBpbnZhc2lvbiBhbmFseXNpcwojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIyBpbXBvcnQgaW4gZGF0YSAoYWxyZWFkeSAyMCBkYXlzICkKYGBge3J9CmludmFkZS5kZiA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2NpX2ludmFzaW9uLmNzdiIpKQpgYGAKCgojIHByb2Nlc3MgZGF0YSBmb3IgaW52YXNpb24gbWF0cml4CmBgYHtyfQppbnZhZGUubWF0IDwtIGludmFkZS5kZiAlPiUgCiAgZ3JvdXBfYnkoVjEgPSBwbWluKG11dF9pZCwgcmVzX2lkKSwgVjIgPSBwbWF4KG11dF9pZCwgcmVzX2lkKSkgJT4lICMgZ3JvdXAgYnkgY3VlIGNvbXBldGl0aW9uLCBpcnJlZ2FyZGxlc3Mgb2Ygb3JkZXIKICBtdXRhdGUoaWRfYWx0ID0gcGFzdGUwKFYxLCBWMiksCiAgICAgICAgIGludmFkZSA9IGNhc2Vfd2hlbigKICAgICAgICAgICBmaXRuZXNzID4gMCB+ICJpbnZhZGUiLAogICAgICAgICAgIGZpdG5lc3MgPCAwIH4gIm5vdCBpbnZhZGUiCiAgICAgICAgICkpICU+JSAKICBncm91cF9ieShpZF9hbHQpICU+JSAKICBtdXRhdGUoCiAgICBtdXRfaXNfVjEgPSBjYXNlX3doZW4oCiAgICBtdXRfaWQgPT0gVjEgfiAiVjFfaW52YWRlIiwKICAgIG11dF9pZCAhPSBWMSB+ICJWMV9pbnZhZGVkIikpICU+JSAKICBhcnJhbmdlKGlkX2FsdCkgJT4lIAogIHNlbGVjdChmaXRuZXNzLCBWMSwgVjIsIGlkX2FsdCwgaW52YWRlLCBtdXRfaXNfVjEpICU+JSAKICB0aWR5cjo6cGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IG11dF9pc19WMSwgdmFsdWVzX2Zyb20gPSBmaXRuZXNzKSAlPiUgCiAgZ3JvdXBfYnkoaWRfYWx0KSAlPiUgCiAgbXV0YXRlKFYxX2ludmFkZTIgPSBnc3ViKCJOQSIsICIiLCBwYXN0ZTAoVjFfaW52YWRlLCBjb2xsYXBzZSA9ICIiKSksCiAgICAgICAgIFYxX2ludmFkZWQyID0gZ3N1YigiTkEiLCAiIiwgcGFzdGUwKFYxX2ludmFkZWQsIGNvbGxhcHNlID0gIiIpKSkgJT4lIAogIGRpc3RpbmN0KGlkX2FsdCwgLmtlZXBfYWxsID0gVCkgJT4lIAogIG11dGF0ZSgKICAgIGNhdGVnb3J5ID0gY2FzZV93aGVuKAogICAgVjFfaW52YWRlMiA+IDAgJiBWMV9pbnZhZGVkMiA+IDAgfiAiTXV0dWFsIGludmFzaW9uIiwKICAgIFYxX2ludmFkZTIgPiAwICYgVjFfaW52YWRlZDIgPCAwIH4gIk9ubHkgc3RyYWluIDEgaW52YXNpb24iLAogICAgVjFfaW52YWRlMiA8IDAgJiBWMV9pbnZhZGVkMiA+IDAgfiAiT25seSBzdHJhaW4gMiBpbnZhc2lvbiIsCiAgICBWMV9pbnZhZGUyIDwgMCAmIFYxX2ludmFkZWQyIDwgMCB+ICJNdXR1YWwgbm9uLWludmFzaW9uIgogICkpICU+JSAKICBzZWxlY3QoVjEsIFYyLCBpbnZhc2lvbiA9IGNhdGVnb3J5KQoKaW52YWRlLmRmICU+JSBmaWx0ZXIobXV0X2lkID09ICJHLWlfbm9uZSIpCmludmFkZS5kZiAlPiUgZmlsdGVyKHJlc19pZCA9PSAiRy1pX25vbmUiKQpgYGAKCgpgYGB7cn0KIyBmb3IgcGxvdHRpbmcsIG5lZWQgdG8gZ2V0IGFsbCBzYW1lIGN1ZSB2cyBzYW1lIGN1ZSwgd2hpY2ggd2Ugd2lsbCBzZXQgdG8gTkEKaW52YWRlLk5BIDwtIGNiaW5kLmRhdGEuZnJhbWUoYFYxYCA9IHVuaXF1ZShpbnZhZGUubWF0JFYxKSwKICAgICAgYFYyYCA9IHVuaXF1ZShpbnZhZGUubWF0JFYxKSwKICAgICAgaW52YXNpb24gPSBOQSkKCmludmFkZS5tYXQyIDwtIHJiaW5kKGludmFkZS5tYXQsIGludmFkZS5OQSkKCiMgZ2V0IGxhYmVsCmludmFkZS5tYXQzIDwtIGludmFkZS5tYXQyICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGV6X2xhYmVsLCBpZF9jaSwgVjFfbGFiZWwgPSBsYWJlbF9jaSksIGJ5ID0gYygiVjEiID0gImlkX2NpIikpICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGV6X2xhYmVsLCBpZF9jaSwgVjJfbGFiZWwgPSBsYWJlbF9jaSksIGJ5ID0gYygiVjIiID0gImlkX2NpIikpICU+JSAKICBtdXRhdGUoVjFfbGFiZWwgPSBnc3ViKCJsb2ciLCAibG9nMTAiLCBWMV9sYWJlbCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVjJfbGFiZWwgPSBnc3ViKCJsb2ciLCAibG9nMTAiLCBWMl9sYWJlbCkpCgoKaW52YWRlLm1hdDQgPC0gcmJpbmQoCiAgc2VsZWN0KGludmFkZS5tYXQzLCBWMV9sYWJlbCwgVjJfbGFiZWwsIGludmFzaW9uKSwKICBzZWxlY3QoaW52YWRlLm1hdDMsIFYyX2xhYmVsID0gVjFfbGFiZWwsIFYxX2xhYmVsID0gVjJfbGFiZWwpICU+JSBtdXRhdGUoaW52YXNpb24gPSBOQSkpICU+JQogIG11dGF0ZSgKICAgIGludmFzaW9uXzIgPSBjYXNlX3doZW4oCiAgICBpbnZhc2lvbiA9PSAiTXV0dWFsIGludmFzaW9uIiB+ICJNdXR1YWwgaW52YXNpb24iLAogICAgaW52YXNpb24gPT0gIk9ubHkgc3RyYWluIDEgaW52YXNpb24iIH4gIkNvbXBldGl0aXZlIGV4Y2x1c2lvblxub2YgYW5vdGhlciBjdWUiLAogICAgaW52YXNpb24gPT0gIk9ubHkgc3RyYWluIDIgaW52YXNpb24iIH4gIkNvbXBldGl0aXZlIGV4Y2x1c2lvblxuYnkgYW5vdGhlciBjdWUiCiAgKSkgJT4lIAogIGZpbHRlcighaXMubmEoVjFfbGFiZWwpKQoKaW52YWRlLm1hdDQkVjFfbGFiZWwgPC0gZmFjdG9yKGludmFkZS5tYXQ0JFYxX2xhYmVsLCBsZXZlbHMgPSAgYygiRyBsb2cxMCIsICJHIiwgIkcxK0cyIiwgIkkgbG9nMTAiLCAiSSIsICJJK0lnIGxvZzEwIiwgIkkrSWciLCAiSTErSTIgbG9nMTAiLCAiSTErSTIiLCAiSWcgbG9nMTAiLCAiSWciLCAiSWcxK0lnMiIsICJSIGxvZzEwIiwgIlIiLCAic3VtIGxvZzEwIiwgInN1bSIpKQppbnZhZGUubWF0NCRWMl9sYWJlbCA8LSBmYWN0b3IoaW52YWRlLm1hdDQkVjJfbGFiZWwsIGxldmVscyA9ICBjKCJHIiwgIkcxK0cyIiwgIkkgbG9nMTAiLCAiSSIsICJJK0lnIGxvZzEwIiwgIkkrSWciLCAiSTErSTIgbG9nMTAiLCAiSTErSTIiLCAiSWcgbG9nMTAiLCAiSWciLCAiSWcxK0lnMiIsICJSIGxvZzEwIiwgIlIiLCAic3VtIGxvZzEwIiwgInN1bSIsICJHIGxvZzEwIikpCmBgYAoKCiMgcGxvdCBpbnZhc2lvbiBtYXRyaXgKYGBge3J9CmludmFzaW9uLnBsMSA8LSBnZ3Bsb3QoZGF0YSA9IGludmFkZS5tYXQ0LCBhZXMoeCA9IFYyX2xhYmVsLCB5ID0gVjFfbGFiZWwsIGZpbGwgPSBpbnZhc2lvbl8yKSkgKwogIGdlb21fdGlsZShjb2xvciA9ICJibGFjayIpICsKICB0aGVtZV9taW5pbWFsKCkgKyAgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwKICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCB2anVzdCA9IDEsIGhqdXN0ID0gMSksCiAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksCiAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksCiAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICBwbG90Lm1hcmdpbj1tYXJnaW4ociA9IDApKSArIAogIGxhYnMoZmlsbCA9ICJJbnZhc2liaWxpdHkiLCB4ID0gIkNvbXBldGluZyBjdWUiLCB5ID0gIlJlZmVyZW5jZSBjdWUiKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSByZXYpICsKICBzY2FsZV95X2Rpc2NyZXRlKGxpbWl0cyA9IHJldikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIkNvbXBldGl0aXZlIGV4Y2x1c2lvblxub2YgYW5vdGhlciBjdWUiID0gIiM0NTc1YjQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNvbXBldGl0aXZlIGV4Y2x1c2lvblxuYnkgYW5vdGhlciBjdWUiID0gIiNmYzhkNTkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk11dHVhbCBpbnZhc2lvbiIgPSAiI2ZlZTA5MCIpLAogICAgICAgICAgICAgICAgICAgIG5hLnZhbHVlID0gIndoaXRlIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgojIGNyZWF0ZSBzdW1tYXJ5IGJhciBjaGFydApgYGB7cn0KIyBjcmVhdGUgYSBzdGFja2VkIGJhcmNoYXJ0IGZvciBzdW1tYXJ5CiMjIGZpbHRlciBvdXQgbmEKaW52YWRlLm1hdGFsdCA8LSBpbnZhZGUubWF0MyAlPiUgbmEuZXhjbHVkZSgpCgojIGdldCBmcnF1ZW5jeSBmcm9tIGJvdGggc2lkZXMuIE5vdGUgd2hlbiBncm91cGluZyBmb3IgVjIsIGZyb20gdGhlIHBlcnNwZWN0aXZlIG9mIGN1ZSAyLCBzY2VuYXJyaW8gd2hlbiBzdHJhaW4gMiBpbnZhZGUgPSBzdHJhaW4gMSBpbnZhZGUKaW52YWRlLm1hdGFsdDEgPC0gaW52YWRlLm1hdGFsdCAlPiUgZ3JvdXBfYnkoVjFfbGFiZWwsIGludmFzaW9uKSAlPiUgCiAgc3VtbWFyaXplKGZyZXF1ZW5jeV8xID0gbigpKQoKaW52YWRlLm1hdGFsdDIgPC0gaW52YWRlLm1hdGFsdCAlPiUKICBtdXRhdGUoaW52YXNpb25fYWx0ID0gY2FzZV93aGVuKAogICAgaW52YXNpb24gPT0gIk9ubHkgc3RyYWluIDEgaW52YXNpb24iIH4gIk9ubHkgc3RyYWluIDIgaW52YXNpb24iLAogICAgaW52YXNpb24gPT0gIk9ubHkgc3RyYWluIDIgaW52YXNpb24iIH4gIk9ubHkgc3RyYWluIDEgaW52YXNpb24iLAogICAgaW52YXNpb24gPT0gIk11dHVhbCBpbnZhc2lvbiIgfiAiTXV0dWFsIGludmFzaW9uIiwKICAgIGludmFzaW9uID09ICJNdXR1YWwgbm9uLWludmFzaW9uIiB+ICJNdXR1YWwgbm9uLWludmFzaW9uIgogICkpICU+JSAKICBncm91cF9ieShWMl9sYWJlbCwgaW52YXNpb25fYWx0KSAlPiUgCiAgc3VtbWFyaXplKGZyZXF1ZW5jeV8yID0gbigpKSAgICAgCgojIGZ1bGwgam9pbiBhbmQgc3VtLiBoYXMgY29uZmlybWVkIGFsbCBvZiB0aGVtIGFkZCB1cCB0byAxNCAKaW52YWRlLm1hdGFsdDMgPC0gZnVsbF9qb2luKGludmFkZS5tYXRhbHQxLCBpbnZhZGUubWF0YWx0MiwgYnkgPSBjKCJWMV9sYWJlbCIgPSAiVjJfbGFiZWwiLCAiaW52YXNpb24iID0gImludmFzaW9uX2FsdCIpKQoKaW52YWRlLm1hdGFsdDNbaXMubmEoaW52YWRlLm1hdGFsdDMpXSA8LSAwCmludmFkZS5tYXRhbHQ0IDwtIGludmFkZS5tYXRhbHQzICU+JSAKICBtdXRhdGUoZnJlcSA9IGZyZXF1ZW5jeV8xICsgZnJlcXVlbmN5XzIpICU+JSAKICBtdXRhdGUodGVtcCA9IGNhc2Vfd2hlbigKICAgIGludmFzaW9uID09ICJPbmx5IHN0cmFpbiAxIGludmFzaW9uIiB+IGZyZXEKICApKSAlPiUgCiAgZ3JvdXBfYnkoVjFfbGFiZWwpICU+JSAKICBtdXRhdGUoaW52YWRlXzFfZnJlcSA9IG1heCh0ZW1wLCBuYS5ybSA9IFQpKSAlPiUgCiAgbXV0YXRlKGludmFzaW9uXzIgPSBjYXNlX3doZW4oCiAgICBpbnZhc2lvbiA9PSAiTXV0dWFsIGludmFzaW9uIiB+ICJNdXR1YWwgaW52YXNpb24iLAogICAgaW52YXNpb24gPT0gIk9ubHkgc3RyYWluIDEgaW52YXNpb24iIH4gIkNvbXBldGl0aXZlIGV4Y2x1c2lvblxub2YgYW5vdGhlciBjdWUiLAogICAgaW52YXNpb24gPT0gIk9ubHkgc3RyYWluIDIgaW52YXNpb24iIH4gIkNvbXBldGl0aXZlIGV4Y2x1c2lvblxuYnkgYW5vdGhlciBjdWUiCiAgKSkKYGBgCgoKCmBgYHtyfQppbnZhc2lvbi5wbDIgPC0gZ2dwbG90KCkgKwogIGdlb21fYmFyKGRhdGEgPSBpbnZhZGUubWF0YWx0NCwgYWVzKHggPSBmcmVxLCB5ID0gcmVvcmRlcihWMV9sYWJlbCwgaW52YWRlXzFfZnJlcSksIGZpbGwgPSBmb3JjYXRzOjpmY3RfcmV2KGZhY3RvcihpbnZhc2lvbl8yLCBsZXZlbHMgPSBjKCJDb21wZXRpdGl2ZSBleGNsdXNpb25cbm9mIGFub3RoZXIgY3VlIiwgIkNvbXBldGl0aXZlIGV4Y2x1c2lvblxuYnkgYW5vdGhlciBjdWUiLCAiTXV0dWFsIGludmFzaW9uIiwgIk11dHVhbCBub24taW52YXNpb24iKSkpKSwgc3RhdCA9ICJpZGVudGl0eSIpICsKICBsYWJzKHggPSAiRnJlcXVlbmN5IiwgZmlsbCA9ICJJbnZhc2liaWxpdHkiLCB5ID0gIkN1ZSIpICsKICB0aGVtZV9idygpICArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiQ29tcGV0aXRpdmUgZXhjbHVzaW9uXG5vZiBhbm90aGVyIGN1ZSIgPSAiIzQ1NzViNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ29tcGV0aXRpdmUgZXhjbHVzaW9uXG5ieSBhbm90aGVyIGN1ZSIgPSAiI2ZjOGQ1OSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTXV0dWFsIGludmFzaW9uIiA9ICIjZmVlMDkwIikpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSkpCmBgYAoKIyBwbG90IHRvZ2V0aGVyCmBgYHtyfQpnZ2FycmFuZ2UoaW52YXNpb24ucGwxLCBpbnZhc2lvbi5wbDIsIGFsaWduID0gImgiLCBjb21tb24ubGVnZW5kID0gVCwgd2lkdGhzID0gYygyLCAxKSkKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vaW52YXNpb25fYS50aWZmIiksIHVuaXRzID0gInB4Iiwgd2lkdGggPSAyMjUwLCBoZWlnaHQgPSAxMTAwLCBzY2FsZSA9IDEuNCwgZHBpPTMwMCwgIGJnID0gIndoaXRlIikKYGBgCgojLS0tLS0tLS0tLS0tLS0tLSBpbnZhc2lvbiBwYWlyd2lzZSBjb21wYXJpc29uLS0tLS0tLS0tLS0tLS0tLS0jCiMjIHByb2NlcyBkYXRhCmBgYHtyfQojIGpvaW4gaW52YWRlIGRmIHdpdGggbGFiZWwgYmVjYXVzZSBJIGFtIGxhenkKaW52YWRlLmRmMiA8LSBpbnZhZGUuZGYgJT4lIAogIGxlZnRfam9pbihzZWxlY3QoZXpfbGFiZWwsIGlkX2NpLCBsYWJlbF9jaV8xID0gbGFiZWxfY2kpLCBieSA9IGMoIm11dF9pZCIgPSAiaWRfY2kiKSkKCmludmFkZS5kZjIgCmBgYAoKIyBsb2cKYGBge3J9CiMgZ2V0IG5vbi1sb2dnZWQgcGFpcmluZ3MKaW52YWRlX25vbG9nIDwtIGludmFkZS5kZjIgJT4lIAogIG11dGF0ZShjdWVfMSA9IHRyaW13cyhnc3ViKCJcXCAuKiIsICIiLCBsYWJlbF9jaV8xKSksCiAgICAgICAgIGxvZ18xID0gY2FzZV93aGVuKAogICAgICAgICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgImxvZyIpIH4gImxvZyIsCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIiwgbmVnYXRlID0gVCkgfiAibm9uZSIpKSAlPiUgCiAgZmlsdGVyKGxvZ18xID09ICJub25lIikKCgppbnZhZGVfbG9nIDwtIGludmFkZS5kZjIgJT4lIAogIG11dGF0ZShjdWVfMSA9IHRyaW13cyhnc3ViKCJcXCAuKiIsICIiLCBsYWJlbF9jaV8xKSksCiAgICAgICAgIGxvZ18xID0gY2FzZV93aGVuKAogICAgICAgICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgImxvZyIpIH4gImxvZyIsCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIiwgbmVnYXRlID0gVCkgfiAibm9uZSIpKSAlPiUgCiAgZmlsdGVyKGxvZ18xID09ICJsb2ciKQoKaW52YWRlX2xvZy5kZiA8LSBsZWZ0X2pvaW4oCiAgc2VsZWN0KGludmFkZV9ub2xvZywgY3VlXzEsIHJlc19pZCwgbG9nXzEsIE5vbmUgPSBmaXRuZXNzKSwKICBzZWxlY3QoaW52YWRlX2xvZywgY3VlXzEsIHJlc19pZCwgbG9nXzEsIExvZyA9IGZpdG5lc3MpLAogIGJ5ID0gYygiY3VlXzEiLCAicmVzX2lkIikpICU+JSAKICBmaWx0ZXIoIWlzLm5hKE5vbmUpICYgIWlzLm5hKExvZykpICU+JSAKICBtdXRhdGUoY2xhc3NpZmljYXRpb24gPSBpZmVsc2UoTG9nID4gTm9uZSwgIkxvZ2dlZCBiZXR0ZXIiLCAiTm90IGxvZ2dlZCBiZXR0ZXIiKSkKCmludmFkZV9sb2cKYGBgCgojIGNvbWJpbmVkCmBgYHtyfQppbnZhZGVfbm9jb21iIDwtIGludmFkZS5kZjIgJT4lIAogIG11dGF0ZShjdWVfMSA9IGlmZWxzZSgKICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgInN1bSIpLCAiSStJZyIsCiAgICB0cmltd3MoZ3N1YigiKzEuKnxcXCBsb2ciLCAiIiwgbGFiZWxfY2lfMSkpCiAgKSwKICBsb2dfMSA9IGNhc2Vfd2hlbigKICAgICAgICAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJsb2ciKSB+ICJsb2ciLAogICAgICAgICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgImxvZyIsIG5lZ2F0ZSA9IFQpIH4gIm5vbmUiKSwKICAgIGNvbWJfMSA9IGNhc2Vfd2hlbigKICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgIjErfHN1bSIpIH4gImNvbWIiLAogICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAiMSt8c3VtIiwgbmVnYXRlID0gVCkgfiAibm9uZSIgCiAgKSkgJT4lIAogIGZpbHRlcihjb21iXzEgPT0gIm5vbmUiKQoKaW52YWRlX2NvbWIgPC0gaW52YWRlLmRmMiAlPiUgCiAgbXV0YXRlKGN1ZV8xID0gaWZlbHNlKAogICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAic3VtIiksICJJK0lnIiwKICAgIHRyaW13cyhnc3ViKCIrMS4qfFxcIGxvZyIsICIiLCBsYWJlbF9jaV8xKSkKICApLAogIGxvZ18xID0gY2FzZV93aGVuKAogICAgICAgICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgImxvZyIpIH4gImxvZyIsCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIiwgbmVnYXRlID0gVCkgfiAibm9uZSIpLAogICAgY29tYl8xID0gY2FzZV93aGVuKAogICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAiMSt8c3VtIikgfiAiY29tYiIsCiAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICIxK3xzdW0iLCBuZWdhdGUgPSBUKSB+ICJub25lIiAKICApKSAlPiUgCiAgZmlsdGVyKGNvbWJfMSA9PSAiY29tYiIpCiAgCmludmFkZV9jb21iLmRmIDwtIGxlZnRfam9pbigKICBzZWxlY3QoaW52YWRlX25vY29tYiwgY3VlXzEsIHJlc19pZCwgbG9nXzEsIFNlbGYgPSBmaXRuZXNzKSwKICBzZWxlY3QoaW52YWRlX2NvbWIsIGN1ZV8xLCByZXNfaWQsIGxvZ18xLCBUb3RhbCA9IGZpdG5lc3MpLAogIGJ5ID0gYygiY3VlXzEiLCAibG9nXzEiLCAicmVzX2lkIikpICU+JSAKICBmaWx0ZXIoIWlzLm5hKFRvdGFsKSAmICFpcy5uYShTZWxmKSkgJT4lIAogIG11dGF0ZShjbGFzc2lmaWNhdGlvbiA9IGlmZWxzZShUb3RhbCA+IFNlbGYsICJUb3RhbCBiZXR0ZXIiLCAiU2VsZiBiZXR0ZXIiKSkKaW52YWRlX2NvbWIuZGYKYGBgCgojIHBsb3QKYGBge3J9CmludmFkZV9sb2cucGwgPC0gZ2dwYWlyZWQoaW52YWRlX2xvZy5kZiwgY29uZDEgPSAiTm9uZSIsIGNvbmQyID0gIkxvZyIsIGxpbmUuY29sb3IgPSAiY2xhc3NpZmljYXRpb24iLCBhbHBoYSA9IDAuNSkgKwogIGxhYnMoeCA9ICJDdWUgcGVyY2VwdGlvbiIsIHkgPSAiRml0bmVzcyBkaWZmZXJlbmNlIiwgY29sb3IgPSAiRWZmZWN0IikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJOb3QgbG9nZ2VkIGJldHRlciIgPSAiI2ZjOGQ1OSIsICJMb2dnZWQgYmV0dGVyIiA9ICIjNDU3NWI0IikpKwogIHN0YXRfY29tcGFyZV9tZWFucyhwYWlyZWQgPSBUUlVFLCBoanVzdCA9IC0wKQoKaW52YWRlX2NvbWIucGwgPC0gZ2dwYWlyZWQoaW52YWRlX2NvbWIuZGYsIGNvbmQxID0gIlRvdGFsIiwgY29uZDIgPSAiU2VsZiIsIGxpbmUuY29sb3IgPSAiY2xhc3NpZmljYXRpb24iLCBhbHBoYSA9IDAuNSkgKwogIGxhYnMoeCA9ICJDdWUgcGVyY2VwdGlvbiIsIHkgPSAiRml0bmVzcyBkaWZmZXJlbmNlIiwgY29sb3IgPSAiRWZmZWN0IikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJUb3RhbCBiZXR0ZXIiID0gIiNmYzhkNTkiLCAiU2VsZiBiZXR0ZXIiID0gIiM0NTc1YjQiKSkrCiAgc3RhdF9jb21wYXJlX21lYW5zKHBhaXJlZCA9IFRSVUUsIGhqdXN0ID0gLTApCgpnZ2FycmFuZ2UoaW52YWRlX2xvZy5wbCwgaW52YWRlX2NvbWIucGwsIGFsaWduID0gImgiLCBuY29sID0gMikKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vaW52YXNpb25fYi50aWZmIiksIHVuaXRzID0gInB4Iiwgd2lkdGggPSAyMjUwLCBoZWlnaHQgPSA5MDAsIHNjYWxlID0gMS4yLCBkcGk9MzAwLCAgYmcgPSAid2hpdGUiKQpgYGAKCgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIyBDdWUgcGVyZm9ybWFuY2UgYWNyb3NzIHNpbmdsZSwgY28taW5mZWN0aW9uLCBzdGF0aWMsIGFuZCBpbnZhc2lvbgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKYGBge3J9CiMgaW1wb3J0IGluIGFsbCB0aGUgcmFua3MKc2lfb3B0LmRmIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvc2lfb3B0LmNzdiIpKQpjaV9vcHQuZGYgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9jaV9vcHQuY3N2IikpCnN0YXRpYy5kZiA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2NpX3N0YXRpYy5jc3YiKSkKaW52YXNpb24uZGYgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9jaV9pbnZhc2lvbi5jc3YiKSkKCiMgY2FsY3VsYXRlIG1lYW4gZml0bmVzcwpzdGF0aWMubWVhbiAjIyBhbHJlYWR5IGNhbGN1bGF0ZWQKaW52YXNpb24ubWVhbiA8LSByYmluZChzZWxlY3QoaW52YXNpb24uZGYsIGN1ZSA9IG11dF9pZCwgZml0bmVzcyksCiAgICAgIHNlbGVjdChpbnZhc2lvbi5kZiAlPiUgbXV0YXRlKGZpdG5lc3MyID0gZml0bmVzcyAqIC0xKSwgY3VlID0gcmVzX2lkLCBmaXRuZXNzID0gZml0bmVzczIpKSAlPiUgCiAgZ3JvdXBfYnkoY3VlKSAlPiUgCiAgc3VtbWFyaXplKG1lYW5fZml0bmVzcyA9IG1lYW4oZml0bmVzcykpICU+JSAKICBhcnJhbmdlKGRlc2MobWVhbl9maXRuZXNzKSkKCiMgY2FsY3VsYXRlIHJhbmtzCnNpLnJhbmsgPC0gc2lfb3B0LmRmICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGV6X2xhYmVsLCBpZF9jaSwgaWRfc2ksIGxhYmVsID0gZXpfbGFiZWxfc2kpLCBieSA9IGMoImlkIiA9ICJpZF9zaSIpKSAlPiUgCiAgbXV0YXRlKHJhbmsgPSBkZW5zZV9yYW5rKC1maXRuZXNzXzIwKSwKICAgICAgICAgbW9kZWwgPSAiU2luZ2xlIGluZmVjdGlvbiIpICU+JSAKICBzZWxlY3QocmFuaywgbW9kZWwsIGlkID0gaWRfY2ksIGxhYmVsKQoKY2kucmFuayA8LSBjaV9vcHQuZGYgJT4lIAogIGxlZnRfam9pbihzZWxlY3QoY2lfZml0bmVzcy5kZiwgdmFsdWUsIGxhYmVsKSwgYnkgPSAibGFiZWwiKSAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChlel9sYWJlbCwgaWRfY2ksIGlkX3NpLCBlel9sYWJlbCksIGJ5ID0gYygiaWQiID0gImlkX2NpIikpICU+JSAKICBtdXRhdGUocmFuayA9IHJhbmsoLXZhbHVlKSwKICAgICAgICAgbW9kZWwgPSAiQ28taW5mZWN0aW9uIikgJT4lIAogIHNlbGVjdChyYW5rLCBtb2RlbCwgaWQsIGxhYmVsID0gZXpfbGFiZWwpCgpzdGF0aWMucmFuayA8LSBzdGF0aWMubWVhbiAlPiUgCiAgbXV0YXRlKGxhYmVsX2NpID0gZ3N1YigibG9nMTAiLCAibG9nIiwgbGFiZWxfY2lfMSkpICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGV6X2xhYmVsLCBpZF9jaSwgbGFiZWxfY2ksIGV6X2xhYmVsKSwgYnkgPSBjKCJsYWJlbF9jaSIgPSAibGFiZWxfY2kiKSkgJT4lIAogIG11dGF0ZShyYW5rID0gcmFuaygtbWVhbl9maXRuZXNzKSwKICAgICAgICAgbW9kZWwgPSAiU3RhdGljIG1peGVkIGdlbm90eXBlIikgJT4lIAogIHNlbGVjdChyYW5rLCBtb2RlbCwgaWQgPSBpZF9jaSwgbGFiZWwgPSBlel9sYWJlbCkKCmludmFzaW9uLnJhbmsgPC0gaW52YXNpb24ubWVhbiAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChlel9sYWJlbCwgaWRfY2ksIGV6X2xhYmVsKSwgYnkgPSBjKCJjdWUiID0gImlkX2NpIikpICU+JSAKICBtdXRhdGUocmFuayA9IHJhbmsoLW1lYW5fZml0bmVzcyksCiAgICAgICAgIG1vZGVsID0gIkludmFzaXZlIG1peGVkIGdlbm90eXBlIikgJT4lIAogIHNlbGVjdChyYW5rLCBtb2RlbCwgaWQgPSBjdWUsIGxhYmVsID0gZXpfbGFiZWwpICU+JSAKICBtdXRhdGUobGFiZWwgPSBnc3ViKCJcbiIsICIgIiwgcGFzdGUwKCIgICAiLCBsYWJlbCkpKQoKc3RhdGljLnJhbmsKIyBjb25jYXRlbmF0ZQpmaXRuZXNzLnJhbmsgPC0gcmJpbmQoCiAgc2kucmFuaywgY2kucmFuaywgc3RhdGljLnJhbmssIGludmFzaW9uLnJhbmsKKSAlPiUgCiAgbXV0YXRlKG1vZGVsID0gZmN0X3JlbGV2ZWwobW9kZWwsIGMoIlNpbmdsZSBpbmZlY3Rpb24iLCAiQ28taW5mZWN0aW9uIiwgIlN0YXRpYyBtaXhlZCBnZW5vdHlwZSIsICJJbnZhc2l2ZSBtaXhlZCBnZW5vdHlwZSIpKSkKCiMgaGlnaGxpZ2h0IHRoZSBnb29kIG9uZXMKZml0bmVzcy5yYW5rX2dvb2QgPC0gZml0bmVzcy5yYW5rICU+JSAKICBmaWx0ZXIoaWQgJWluJSBjKCJJZy1pX2xvZyIsICJJLWkrSWctaV9sb2ciLCAic3VtX2xvZyIsICJHLWlfbG9nIikpCmBgYAoKIyBwbG90CmBgYHtyfQpsaWJyYXJ5KGdnYnVtcCkKCmdncGxvdCgpICsKICBnZW9tX2J1bXAoZGF0YSA9IGZpdG5lc3MucmFuaywgYWVzKHggPSBtb2RlbCwgeSA9IHJhbmssIGdyb3VwID0gaWQpLCBjb2xvciA9ICJncmV5IikgKwogIGdlb21fcG9pbnQoZGF0YSA9IGZpdG5lc3MucmFuaywgYWVzKHggPSBtb2RlbCwgeSA9IHJhbmssIGdyb3VwID0gaWQpLCBjb2xvciA9ICJncmV5Iiwgc2l6ZSA9IDMpICsKICBnZW9tX2J1bXAoZGF0YSA9IGZpdG5lc3MucmFua19nb29kLCBhZXMoeCA9IG1vZGVsLCB5ID0gcmFuaywgZ3JvdXAgPSBpZCwgY29sb3IgPSBpZCkpICsKICBnZW9tX3BvaW50KGRhdGEgPSBmaXRuZXNzLnJhbmtfZ29vZCwgYWVzKHggPSBtb2RlbCwgeSA9IHJhbmssIGdyb3VwID0gaWQsIGNvbG9yID0gaWQpLCBzaXplID0gMykgKwogIGdlb21fdGV4dChkYXRhID0gaW52YXNpb24ucmFuaywgYWVzKHggPSBtb2RlbCwgeSA9IHJhbmssIGxhYmVsID0gbGFiZWwpLCBzaXplID0gMy41LCBoanVzdCA9IDAsIGluaGVyaXQuYWVzID0gRikgKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZCgpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGNvb3JkX2NhcnRlc2lhbihjbGlwID0gIm9mZiIpICsKICBzY2FsZV95X3JldmVyc2UoKSArCiAgZXhwYW5kX2xpbWl0cyh4ID0gNS41KSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgbGFicyh4ID0gIk1vZGVsIiwgeSA9ICJNZWFuIGZpdG5lc3MgcmFuayIpCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3Bsb3MtYmlvL2ZpdG5lc3NfcmFuay50aWZmIiksIHVuaXRzID0gInB4Iiwgd2lkdGggPSAyMjUwLCBoZWlnaHQgPSAxNTAwLCBzY2FsZSA9IDEsIGRwaT0zMDAsICBiZyA9ICJ3aGl0ZSIpCmBgYAoKCiMtPT09PT09PT09PT09PT09PT09PT09IwojIFBhcnRpdGlvbmluZyBiZXN0IGN1ZQojPT09PT09PT09PT09PT09PT09PT09LSMKIy0tLS0tLS0gc2luZ2xlIGluZmVjdGlvbiAtLS0tLS0tLS0tLSMKIyByZWRvIHNvbWUgb3B0aW1pemF0aW9uIChsb3dlciBmaXRuZXNzIGluIG5vIFIgdGhhbiBkZWZhdWx0KQpgYGB7cn0Kc291cmNlKGhlcmUoImZ1bmN0aW9ucy9jaGFiYXVkaV9zaV9jbGVhbl9SLlIiKSkKc291cmNlKGhlcmUoImZ1bmN0aW9ucy9jaGFiYXVkaV9zaV9jbGVhbl9OLlIiKSkKIyBJIG5vbmUKY2wgPC0gbWFrZUNsdXN0ZXIoZGV0ZWN0Q29yZXMoKSk7IHNldERlZmF1bHRDbHVzdGVyKGNsID0gY2wpCklfbm9fUiA8LSBvcHRpbVBhcmFsbGVsKAogICAgcGFyID0gcmVwKDAuNSw0KSwgIyBzdGFydCBhdCAwLjV4NAogICAgZm4gPSBjaGFiYXVkaV9zaV9jbGVhbl9SLCAKICAgIGNvbnRyb2wgPSBsaXN0KHRyYWNlID0gNiwgZm5zY2FsZSA9IC0xKSwKICAgIGltbXVuaXR5ID0gInRzdWt1c2hpIiwKICAgIHBhcmFtZXRlcnMgPSBwYXJhbWV0ZXJzX3RzdWt1c2hpLAogICAgdGltZV9yYW5nZSA9IHNlcSgwLCAyMCwgYnkgPSAxZS0zKSwKICAgIGN1ZV9yYW5nZSA9ICBzZXEoMCwgNiooMTBeNiksIGJ5ID0gKDYqKDEwXjYpKS81MDAwKSwKICAgIGN1ZSA9ICJJIiwKICAgIGxvZ19jdWUgPSAibm9uZSIsCiAgICBzb2x2ZXIgPSAidm9kZSIpCnN0b3BDbHVzdGVyKGNsKQojIDAuMTQ0MDIxIC00My4xMDQ2IDIwMzAuMjcgLTUyNC42ODYgCiMgOC42OTU4OQpgYGAKCiMgaW1wb3J0IGFuZCBwcm9jZXNzIGRhdGEKYGBge3J9CiMgaW1wb3J0IGluIGRhdGEKc2lfcGFydGl0aW9uLmxzIDwtIGxpc3QuZmlsZXMocGF0aCA9IGhlcmUoImRhdGEvcGFydGl0aW9uL3NpLyIpLCBwYXR0ZXJuID0gIiouY3N2IiwgZnVsbC5uYW1lcyA9IFQpCnNpX3BhcnRpdGlvbi5scyA8LSBsYXBwbHkoc2lfcGFydGl0aW9uLmxzLCByZWFkLmNzdikKc2lfcGFydGl0aW9uLmRmIDwtIGRvLmNhbGwocmJpbmQsIHNpX3BhcnRpdGlvbi5scykKCiMgY29tYmluZSB3aXRoIHNpIGZpdG5lc3MgKGRlZmF1bHQpCnNpX3BhcnRpdGlvbi5kZiA8LSBzaV9wYXJ0aXRpb24uZGYgJT4lIGxlZnRfam9pbihzZWxlY3Qoc2lfZml0bmVzcy5kZiwgaWQsIGZpdG5lc3MgPSB2YWx1ZSksIGJ5ID0gImlkIikKCiMgbWFrZSBsb25nZXIKc2lfcGFydGl0aW9uLmRmMiA8LSB0aWR5cjo6cGl2b3RfbG9uZ2VyKHNpX3BhcnRpdGlvbi5kZiwgYyhmaXRuZXNzX1IsIGZpdG5lc3NfTiwgZml0bmVzc19XLCBmaXRuZXNzKSkKCiMgY2FsY3VsYXRlIGNvZWZmaWNpZW50IG9mIHZhcmlhdGlvbi4gQWxzbyByZW5hbWUKc2lfcGFydGl0aW9uLmRmMiA8LSBzaV9wYXJ0aXRpb24uZGYyICU+JSAKICBncm91cF9ieShuYW1lKSAlPiUgCiAgbXV0YXRlKGN2ID0gc2QodmFsdWUpL21lYW4odmFsdWUpKjEwMCwKICAgICAgICAgbWVhbiA9IG1lYW4odmFsdWUpLAogICAgICAgICBjYXRlZ29yeSA9IGNhc2Vfd2hlbigKICAgICAgICAgICBuYW1lID09ICJmaXRuZXNzX1IiIH4gIk5vIFJCQyBsaW1pdGF0aW9uIiwKICAgICAgICAgICBuYW1lID09ICJmaXRuZXNzX1ciIH4gIk5vIHRhcmdldGVkIGltbXVuaXR5IiwKICAgICAgICAgICBuYW1lID09ICJmaXRuZXNzX04iIH4gIk5vIGluZGlzY3JpbWluYXRlXG5pbW11bml0eSIsCiAgICAgICAgICAgbmFtZSA9PSAiZml0bmVzcyIgfiAiRGVmYXVsdCIKICAgICAgICAgKSkKCmBgYAoKIyBwbG90CmBgYHtyfQpsaWJyYXJ5KHVuZ2V2aXopCiMgcmF3IGZpdG5lc3MKc2lfcGFydGl0aW9uLnBsMSA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV92cGxpbmUoZGF0YSA9IHNpX3BhcnRpdGlvbi5kZjIsIGFlcyh5ID0gZmN0X3Jlb3JkZXIoY2F0ZWdvcnksIG1lYW4pLCB4ID0gbWVhbiwgZ3JvdXAgPSBjYXRlZ29yeSwgY29sb3IgPSBjYXRlZ29yeSksIHNob3cubGVnZW5kID0gRiwgc2l6ZSA9IDEpICsKICBnZW9tX3BvaW50KGRhdGEgPSBzaV9wYXJ0aXRpb24uZGYyLCBhZXMoeSA9IGZjdF9yZW9yZGVyKGNhdGVnb3J5LCBtZWFuKSwgeCA9IHZhbHVlKSwgc2l6ZSA9IDIsIGFscGhhID0gMC43KSArCiAgZ2VvbV9saW5lKGRhdGEgPSBzaV9wYXJ0aXRpb24uZGYyLCBhZXMoeSA9IGZjdF9yZW9yZGVyKGNhdGVnb3J5LCBtZWFuKSwgeCA9IHZhbHVlLCBncm91cCA9IGlkKSwgYWxwaGEgPSAwLjIpICsKICBsYWJzKHggPSAiRml0bmVzcyIsIHkgPSAiQ29uZGl0aW9ucyIpICsKICB0aGVtZV9idygpCgojIGNvZWZmaWNpZW50IG9mIHZhcmlhdGlvbgpzaV9wYXJ0aXRpb24ucGwyIDwtIGdncGxvdCgpICsKICBnZW9tX2JhcihkYXRhID0gc2lfcGFydGl0aW9uLmRmMiwgYWVzKHkgPSBmY3RfcmVvcmRlcihjYXRlZ29yeSwgbWVhbiksIHggPSBjdiksIHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgbGFicyh4ID0gIkNvZWZmaWNpZW50IG9mXG52YXJpYXRpb24gKCUpIiwgeSA9ICIiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50aXRsZS55PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55PWVsZW1lbnRfYmxhbmsoKSkKCnNpX3BhcnRpdGlvbi5wbCA8LSBnZ2FycmFuZ2Uoc2lfcGFydGl0aW9uLnBsMSwgc2lfcGFydGl0aW9uLnBsMiwgd2lkdGhzID0gYygxLCAwLjMpLCBhbGlnbiA9ICJoIikKc2lfcGFydGl0aW9uLnBsCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby9wYXJ0aXRpb25fZml0bmVzcy50aWZmIiksIHdpZHRoID0gNywgaGVpZ2h0ID0gNCkKYGBgCgojLS0tLS0tLSBjb25zZXF1ZW5jZXMgb2Ygbm8gdGFyZ2V0ZWQgaW1tdW5pdHkgLS0tLS0tLS0tLS0tIwojIGdldCBkeW5hbWljcyBvZiBubyB0YXJnZXRlZCBpbW11bml0eQpgYGB7cn0KZ2V0X2R5biA8LSBmdW5jdGlvbihkZil7CiAgCiAgc291cmNlKGhlcmUoImZ1bmN0aW9ucy9jaGFiYXVkaV9zaV9jbGVhbl9XLlIiKSkKICBpZCA8LSBkZiRpZAogIGN1ZSA8LSBkZiRjdWUKICBsb2cgPC0gZGYkbG9nCiAgcGFyIDwtIGMoZGYkdmFyX1cxLCBkZiR2YXJfVzIsIGRmJHZhcl9XMywgZGYkdmFyX1c0KQogIGN1ZV9yYW5nZSA8LSBzZXEoZGYkbG93LCBkZiRoaWdoLCBieSA9IGRmJGJ5KQogIAogICMgZ2V0IGR5bmFtaWNzCiAgZHluIDwtIGNoYWJhdWRpX3NpX2NsZWFuX1coCiAgICBwYXJhbWV0ZXJzX2NyID0gcGFyLAogICAgaW1tdW5pdHkgPSAidHN1a3VzaGkiLAogICAgcGFyYW1ldGVycyA9IHBhcmFtZXRlcnNfdHN1a3VzaGksCiAgICB0aW1lX3JhbmdlID0gc2VxKDAsIDIwLCBieSA9IDFlLTMpLAogICAgY3VlX3JhbmdlID0gIGN1ZV9yYW5nZSwKICAgIGN1ZSA9IGN1ZSwKICAgIGxvZ19jdWUgPSBsb2csCiAgICBzb2x2ZXIgPSAidm9kZSIsCiAgICBkeW4gPSBUCiAgKQogIAogICMgY29tYmluZQogIGR5bjIgPC0gY2JpbmQoZHluLCBpZCA9IGlkLCBjdWUgPSBjdWUsIGxvZyA9IGxvZykKICAKICB3cml0ZV9wYXJxdWV0KGR5bjIsIHBhc3RlMChoZXJlKCJkYXRhL3BhcnRpdGlvbi9zaV9keW4vIiksIGlkLCAiX25vV19keW4ucGFycXVldCIpKQogIAp9CmBgYAoKIyBnZXQgZGYgdG8gcnVuCmBgYHtyfQojIGpvaW4gd2l0aCBjdWVfcmFuZ2UKY3VlX3JhbmdlX3NpLmRmIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvY3VlX3JhbmdlX3NpLmNzdiIpKQpzaV9wYXJ0aXRpb24uZGYzIDwtIHNpX3BhcnRpdGlvbi5kZiAlPiUgbGVmdF9qb2luKHNlbGVjdChjdWVfcmFuZ2Vfc2kuZGYsIGxvdywgaGlnaCwgYnksIGlkKSwgImlkIikKCiMgbGFwcGx5IGxvb3AKc2lfcGFydGl0aW9uLmxzIDwtIHNwbGl0KHNpX3BhcnRpdGlvbi5kZjMsIHNlcShucm93KHNpX3BhcnRpdGlvbi5kZjMpKSkKbWNsYXBwbHkoc2lfcGFydGl0aW9uLmxzLCBnZXRfZHluKQpgYGAKCiMgcHJvY2VzcyBkYXRhZnJhbWUKYGBge3J9CiMgaW1wb3J0IGluIGRhdGFmcmFtZQpub19XLmxzIDwtIGxpc3QuZmlsZXMoaGVyZSgiZGF0YS9wYXJ0aXRpb24vc2lfZHluLyIpLCBwYXR0ZXJuID0gIipub1dfZHluLnBhcnF1ZXQiLCBmdWxsLm5hbWVzID0gVCkKbm9fVy5kZiA8LSBsYXBwbHkobm9fVy5scywgcmVhZF9wYXJxdWV0KQpub19XLmRmIDwtIGRvLmNhbGwocmJpbmQsIG5vX1cuZGYpCgojIGNvbWJpbmUgd2l0aCBleiBsYWJlbAplel9sYWJlbCA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2V6X2xhYmVsLmNzdiIpKQpub19XLmRmIDwtIGxlZnRfam9pbihub19XLmRmLCBlel9sYWJlbCwgYnkgPSBjKCJpZCIgPSAiaWRfc2kiKSkKCiMgZ2V0IGNvbnZlcnNpb24gcmF0ZSAKbm9fVy5jciA8LSBub19XLmRmICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gImNyIikKbm9fVy5JIDwtIG5vX1cuZGYgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiSSIpCgojIGdldCBkZWZhdWx0IGNvbnZlcnNpb24gcmF0ZSBkeW5hbWljcwpzaV9keW4uZGYgPC0gbGVmdF9qb2luKHNpX2R5bi5kZiwgZXpfbGFiZWwsIGJ5ID0gYygiaWQiID0gImlkX3NpIikpCnNpX2R5bi5jciA8LSBzaV9keW4uZGYgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiY3IiKQpzaV9keW4uSSA8LSBzaV9keW4uZGYgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiSSIpCmBgYAoKIyBwbG90IGNvbnZlcnNpb24gcmF0ZQptZWNoYW5pc206IHRhcmdldGVkIGltbXVuaXR5IGxlZCB0byBsb3dlciBwYXJhc2l0ZSBkZW5zaXR5IGluIHRoZSBpbml0aWFsIHN0YWdlcywgd2hpY2ggcHJldmVudHMgcGFyYXNpdGVzIGZyb20gbWFraW5nIHRoZSBzd2l0Y2ggZnJvbSBubyBjb252ZXJzaW9uIHJhdGUgdG8gaGlnaCBjb252ZXJzaW9uIHJhdGUuIFdoZW4gcGFyc2l0ZSBkZW5zaXR5IHVuZGVyZ29lcyBkcmFzdGljIGluY3JlYXNlIGF0IHRoZSBiZWdpbm5pbmcgZHVlIHRvIGxvd2VyIGltbXVuaXR5LCB0aGlzIHByZXNlbnRzIGEgaGlnaGVyIGRlZ3JlZSBvZiBzaWduYWwgdGhhdCBhbGxvd3MgcGFyYXNpdGUgdG8gbWFrZSB0aGUgc3dpdGNoIGFwcHJvcHJpYXRlbHkKYGBge3J9CnBhcnRpdGlvbl9jci5wbCA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBub19XLmNyLCBhZXMoeCA9IHRpbWUsIHk9IHZhbHVlLCBjb2xvciA9ICJObyB0YXJnZXRlZCBpbW11bml0eSIpKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBzaV9keW4uY3IsIGFlcyh4ID0gdGltZSwgeT0gdmFsdWUsIGNvbG9yID0gIkRlZmF1bHQiKSkgKwogIGZhY2V0X3dyYXAofmV6X2xhYmVsX3NpLCBuY29sID0gNSkgKwogIHhsaW0oMCwgMjApICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSA3KSArCiAgbGFicyh4ID0gIlRpbWUgKGRheXMpIiwgeSA9ICJDb252ZXJzaW9uIHJhdGUiLCBjb2xvciA9ICJDb25kaXRpb24iKSArCiAgdGhlbWVfYncoKQoKbm9fVy5jcgpgYGAKCiMtLS0tLSBjdWUgc3RhdGUgLS0tLS0tLS0tLS0tLS0jCgojIGZ1bmN0aW9uIHRvIGdldCBjdWUgc3RhdGVzCmBgYHtyfQojIGZ1bmN0aW9uIHRvIGdldCBjdWUgc3RhdGVzCmdldF9jdWVfc3RhdGUgPC0gZnVuY3Rpb24oZGYpewogIGN1ZSA8LSB0cmltd3MoZ3N1YigiX2xvZ3xfbm9uZSIsICIiLCB1bmlxdWUoZGYkaWQpKSkKICBpZihjdWUgIT0gIkkrSWciKXsKICBkZjIgPC0gZGYgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSBjdWUpCiAgaWYoc3RyX2RldGVjdCh1bmlxdWUoZGYkaWQpLCAibG9nIikpewogICAgZGYyIDwtIGRmMiAlPiUgCiAgICAgIG11dGF0ZSh2YWx1ZSA9IGxvZzEwKHZhbHVlKSkKICB9CiAgfQogIAogIGlmKGN1ZSA9PSAiSStJZyIpewogICAgZGYyIDwtIGRmICU+JSBmaWx0ZXIodmFyaWFibGUgJWluJSBjKCJJIiwgIklnIikpICU+JSAKICAgICAgZ3JvdXBfYnkodGltZSkgJT4lIAogICAgICBtdXRhdGUodmFsdWUgPSBzdW0odmFsdWUpKQogICAgCiAgICBpZihzdHJfZGV0ZWN0KHVuaXF1ZShkZiRpZCksICJsb2ciKSl7CiAgICBkZjIgPC0gZGYyICU+JSAKICAgICAgbXV0YXRlKHZhbHVlID0gbG9nMTAodmFsdWUpKQogIH0KICB9CiAgCiAgZGYyJHZhbHVlW2RmMiR2YWx1ZSA9PSAtSW5mXSA8LSAwCiAgCiAgd3JpdGVfcGFycXVldChkZjIsIHBhc3RlMChoZXJlKCJkYXRhL3BhcnRpdGlvbi9zaV9kZWZhdWx0X3N0YXRlLyIpLCB1bmlxdWUoZGYkaWQpLCAiX25vV19zdGF0ZS5wYXJxdWV0IikpCn0KYGBgCgojIHJ1biBmdW5jdGlvbgpgYGB7cn0KIyBzcGxpdCBkeW5hbWljcyBiYXNlZCBvbiBpZApub19XLnNwbGl0IDwtIHNwbGl0KG5vX1cuZGYsIG5vX1cuZGYkaWQpCgojIHJ1biBmdW5jdGlvbgptY2xhcHBseShub19XLnNwbGl0LCBnZXRfY3VlX3N0YXRlKQoKIyBnZXQgZGF0YWZyYW1lCm5vX1cuc3RhdGUgPC0gbGlzdC5maWxlcyhoZXJlKCJkYXRhL3BhcnRpdGlvbi9zaV9zdGF0ZS8iKSwgcGF0dGVybiA9ICIqLnBhcnF1ZXQiLCBmdWxsLm5hbWVzID0gVCkKbm9fVy5zdGF0ZSA8LSBsYXBwbHkobm9fVy5zdGF0ZSwgcmVhZF9wYXJxdWV0KQpub19XLnN0YXRlIDwtIGRvLmNhbGwocmJpbmQsIG5vX1cuc3RhdGUpCm5vX1cuc3RhdGUkdmFsdWVbbm9fVy5zdGF0ZSR2YWx1ZSA8IDBdIDwtIDAKCiMgZ2V0IHNhbWUgZm9yIHNpIGluZmVjdGlvbgpkZWZhdWx0LnNwbGl0IDwtIHNwbGl0KHNpX2R5bi5kZiwgc2lfZHluLmRmJGlkKQptY2xhcHBseShkZWZhdWx0LnNwbGl0LCBnZXRfY3VlX3N0YXRlKQpkZWZhdWx0LnN0YXRlIDwtIGxpc3QuZmlsZXMoaGVyZSgiZGF0YS9wYXJ0aXRpb24vc2lfZGVmYXVsdF9zdGF0ZS8iKSwgcGF0dGVybiA9ICIqLnBhcnF1ZXQiLCBmdWxsLm5hbWVzID0gVCkKZGVmYXVsdC5zdGF0ZSA8LSBsYXBwbHkoZGVmYXVsdC5zdGF0ZSwgcmVhZF9wYXJxdWV0KQpkZWZhdWx0LnN0YXRlIDwtIGRvLmNhbGwocmJpbmQsIGRlZmF1bHQuc3RhdGUpCmRlZmF1bHQuc3RhdGUkdmFsdWVbZGVmYXVsdC5zdGF0ZSR2YWx1ZSA8IDBdIDwtIDAKCiMgbWFudWFsbHkgY29ycmVjdCBub24tbG9nZ2luZwpJX0lnLmNvcnIgPC0gbm9fVy5zdGF0ZSAlPiUgZmlsdGVyKGlkID09ICJJK0lnX2xvZyIpICU+JSAKICBtdXRhdGUodmFsdWUgPSBsb2cxMCh2YWx1ZSkpCklfSWcuY29yciR2YWx1ZVtJX0lnLmNvcnIkdmFsdWUgPCAwXSA8LSAwCgpub19XLnN0YXRlMiA8LSBub19XLnN0YXRlICU+JSBmaWx0ZXIoaWQgIT0gIkkrSWdfbG9nIikKbm9fVy5zdGF0ZTIgPC0gbm9fVy5zdGF0ZTIgJT4lIHJiaW5kKG5vX1cuc3RhdGUyLCBJX0lnLmNvcnIpCmBgYAoKIyBwbG90CmFic2VuY2Ugb2YgdGFyZ2V0ZWQgaW1tdW5pdHkgbGVkIHRvIGRyYXN0aWMgaW5jcmVhc2UgaW4gcGFyYXNpdGUgZGVuc2l0eSBpbiBlYXJseSBwaGFzZXMgb2YgaW5mZWN0aW9uLiBUaGlzIHByb2R1Y2VzIGhpZ2ggc2lnbmFsIGludGVuc2l0eSBmb3IgcGFyYXNpdGUgYW5kIGhvc3QtYmFzZWQgY3VlcywgZXNwZWNpYWxseSBub24tbG9nZ2VkIG9uZXMsIHdoaWNoIGFsbG93cyBmb3Igc3RhdGUgZGlmZmVyZW50YXRpb24uIFdoaWxlIHRoaXMgY2FuIGJlIHZpZXdlZCBhcyBhIG1vZGVsbGluZyBhcnRpZmlhY3QsIGl0IHNob3VsZCBiZSBub3RlZCB0aGF0IHRoZSBsb2dnZWQgY3VlcyBzZWxkb20gY2hhbmdlZCBhcyB0aGVzZSBjaGFuZ2VzIGluIGVhcmx5IGluZmVjdGlvbiBkaWQgbGl0dGxlIHRvIGFsdGVyIHRoZSBhY3R1YWwgZWFybHkgc2lnbmFsIGludGVuc2l0eSBzZW5zZWQgYnkgdGhlIHBhcmFzaXRlLiBJbiBhbiBlbnZpcm9ubWVudCB3aGVyZSB0aGVyZSBpcyBoZXRlcm9nZW5laXR5IGluIGhvc3QgcmVzcG9uc2UsIGFuZCB0aHVzLCBzaWduYWwsIGxvZ2dpbmcgYWxsb3dzIGZvciBwYXJhc2l0ZXMgdG8gYWRhcHQgb3B0aW1hbCBzdHJhdGVneSB3aGVyZWFzIG5vbi1sb2dnZWQgY3VlcyBtdXN0IGNvbnRlbmQgd2l0aCBzZW5zaXRpdml0eSB0byBpbW11bml0eS4KYGBge3J9CiMgZnVuY3Rpb24gdG8gaW5kaXZpZHVhbGx5IHBsb3Qgc3R1ZmYKcGxvdF9zdGF0ZSA8LSBmdW5jdGlvbihkZjEsIGRmMil7CiAgCiAgIyBwbG90IHN0YXRlIGR5bmFtaWNzCiAgc3RhdGVfcGwgPC0gZ2dwbG90KCkgKwogIGdlb21fbGluZShkYXRhID0gZGYxLCBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZSwgY29sb3IgPSBuYW1lLCBncm91cCA9IG5hbWUpKSArCiAgZmFjZXRfd3JhcCh+ZXpfbGFiZWxfc2ksIHNjYWxlcyA9ICJmcmVlIikgKwogIHhsaW0oMSwyMCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsKICBsYWJzKHggPSAiIiwgeSA9ICJDdWUiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID1jKCJEZWZhdWx0IiA9ICIjNDU3NWI0IiwgIk5vIHRhcmdldGVkXG5pbW11bml0eSIgPSAiI2ZjOGQ1OSIpKQogIAogICMgcGxvdCBjb252ZXJzaW9uIHJhdGUgZHluYW1pY3MKICBjcl9wbCA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9yYXN0ZXIoZGF0YSA9IGRmMiwgYWVzKHggPSB0aW1lLCB5ID0gbmFtZSwgZmlsbCA9IHZhbHVlKSkgKwogIHhsaW0oMSwyMCkgKwogIHRoZW1lX2J3KCkgKwogICAgbGFicyh4ID0gIlRpbWUgKGRheXMpIikgKwogIHRoZW1lKGF4aXMudGl0bGUueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICAgIHNjYWxlX2ZpbGxfdmlyaWRpc19jKGxpbSA9IGMoMCwgMSkpCiAgCiAgIyBhcnJhbmdlCiAgZ2dhcnJhbmdlKHN0YXRlX3BsLCBjcl9wbCwgbmNvbCA9IDEsIG5yb3cgPSAyLCBhbGlnbiA9ICJ2IiwgaGVpZ2h0cyA9IGMoMSwgMC40KSkKICBnZ3NhdmUocGFzdGUwKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vcGFydGl0aW9uLyIpLCB1bmlxdWUoZGYxJGlkKSwgIi50aWZmIiksIHdpZHRoID0gNC41LCBoZWlnaHQgPSAzLjUpCn0KYGBgCgojIHNwbGl0CmBgYHtyfQojIGNvbWJpbmUgc3RhdGUKbm9XX2RlZmF1bHQuc3RhdGUgPC0gbGVmdF9qb2luKAogIHNlbGVjdChub19XLnN0YXRlMiwgdGltZSwgYE5vIHRhcmdldGVkXG5pbW11bml0eWAgPSB2YWx1ZSwgaWQsIGV6X2xhYmVsX3NpKSwgCiAgc2VsZWN0KGRlZmF1bHQuc3RhdGUgJT4lIGZpbHRlcih0aW1lIDw9IDIwKSwgdGltZSwgYERlZmF1bHRgID0gdmFsdWUsIGlkLCBlel9sYWJlbF9zaSksIGJ5ID0gYygidGltZSIsICJpZCIsICJlel9sYWJlbF9zaSIpKQoKbm9XX2RlZmF1bHQuc3RhdGUyIDwtIHRpZHlyOjpwaXZvdF9sb25nZXIobm9XX2RlZmF1bHQuc3RhdGUsIGMoYE5vIHRhcmdldGVkXG5pbW11bml0eWAsIGBEZWZhdWx0YCkpCiMgY29tYmluZSBjb252ZXJzaW9uIHJhc3Rlcgpub1dfZGVmYXVsdC5jciA8LSBsZWZ0X2pvaW4oCiAgc2VsZWN0KG5vX1cuY3IsIHRpbWUsIGBObyB0YXJnZXRlZFxuaW1tdW5pdHlgID0gdmFsdWUsIGlkLCBlel9sYWJlbF9zaSksIAogIHNlbGVjdChzaV9keW4uY3IgJT4lIGZpbHRlcih0aW1lIDw9IDIwKSwgdGltZSwgYERlZmF1bHRgID0gdmFsdWUsIGlkLCBlel9sYWJlbF9zaSksIGJ5ID0gYygidGltZSIsICJpZCIsICJlel9sYWJlbF9zaSIpKQpub1dfZGVmYXVsdC5jcjIgPC0gdGlkeXI6OnBpdm90X2xvbmdlcihub1dfZGVmYXVsdC5jciwgYyhgTm8gdGFyZ2V0ZWRcbmltbXVuaXR5YCwgYERlZmF1bHRgKSkKCiMgc3BsaXQKbm9XX2RlZmF1bHRfc3RhdGUubHMgPC0gc3BsaXQobm9XX2RlZmF1bHQuc3RhdGUyLCBub1dfZGVmYXVsdC5zdGF0ZTIkaWQpCm5vV19kZWZhdWx0X2NyLmxzIDwtIHNwbGl0KG5vV19kZWZhdWx0LmNyMiwgbm9XX2RlZmF1bHQuY3IyJGlkKQoKIyBydW4gZnVuY3Rpb24KbWFwcGx5KHBsb3Rfc3RhdGUsIG5vV19kZWZhdWx0X3N0YXRlLmxzLCBub1dfZGVmYXVsdF9jci5scykKYGBgCgojLS0tLS0tLS0gcmVhY3Rpb24gbm9ybXMgb2YgZGVmYXVsdCB2cyBvcHRpbWl6ZWQgLS0tLS0tLS0tLS0tIwojIGdldCByZWFjdGlvbiBub3JtIGFuZCBydWcgZGF0YQpgYGB7cn0Kc291cmNlKGhlcmUoImZ1bmN0aW9ucy9wYXJfdG9fZGYuUiIpKQoKIyBHYW1ldG9jeXRlCmdfbG9nLnJuIDwtIHBhcl90b19kZihwYXIgPSBjKDEuMjExNTIxLAktMy45MzY3NzgsCS0xLjMxMjk0NCwJLTEuMjg1NzEzKSwgY3VlX3JhbmdlID0gc2VxKDAsIGxvZzEwKDYqKDEwXjQpKSwgYnkgPSAobG9nMTAoNiooMTBeNCkpKS81MDAwKSkKZ19sb2cucm4yIDwtIHBhcl90b19kZihwYXIgPSBjKDEuMzkzODYwNTM5LAktNC4yNTMwMDc2MTYsCS0wLjMxMzk0NzAyOSwJLTIuMDAwODU3MzQ0KSwgY3VlX3JhbmdlID0gc2VxKDAsIGxvZzEwKDYqKDEwXjQpKSwgYnkgPSAobG9nMTAoNiooMTBeNCkpKS81MDAwKSkKCmcucm4gPC0gcGFyX3RvX2RmKHBhciA9IGMoMC4wNDA2MTI4OCwJLTkuMzE0NDU5NTgsCTc0LjEzMDE1NTA2LAktNDMxLjU5ODQzNjQpLCBjdWVfcmFuZ2UgPSBzZXEoMCwgNiooMTBeNCksIGJ5ID0gKDYqKDEwXjQpKS81MDAwKSkKZy5ybjIgPC0gcGFyX3RvX2RmKHBhciA9IGMoMC41NDE3MjkwNzMsCS0zLjkwNDYxNjQ0MywJMC44NzQ4NzQxMiwJLTAuNjk0MTc3MDIxKSwgY3VlX3JhbmdlID0gc2VxKDAsIDYqKDEwXjQpLCBieSA9ICg2KigxMF40KSkvNTAwMCkpCgojIEkrSWcKSV9JZ19sb2cucm4gPC0gcGFyX3RvX2RmKHBhciA9IGMoMy41OTQwNDIsCTQuMTU3NzQ0LAktMTMuNTMwNjcyLAkyLjU5OTkwNSksIGN1ZV9yYW5nZSA9IHNlcSgwLCBsb2cxMCg2KigxMF42KSksIGJ5ID0gKGxvZzEwKDYqKDEwXjYpKSkvNTAwMCkpCklfSWdfbG9nLnJuMiA8LSBwYXJfdG9fZGYocGFyID0gYyg2My43MTg5MzgyMiwJLTg3Ljc3NjcxNjAxLAktNTYuNTU0NzU1MTQsCS02Ni4wMjIwOTU0OSksIGN1ZV9yYW5nZSA9IHNlcSgwLCBsb2cxMCg2KigxMF42KSksIGJ5ID0gKGxvZzEwKDYqKDEwXjYpKSkvNTAwMCkpCgpJX0lnLnJuIDwtIHBhcl90b19kZihwYXIgPSBjKDAuMzE1OTI5NywJLTQ2LjExMDQ1NTgsCTEyNTAuNzUyOTA4LAktNi4xOTgyMDkzKSwgY3VlX3JhbmdlID0gc2VxKDAsIDYqKDEwXjYpLCBieSA9ICg2KigxMF42KSkvNTAwMCkpCklfSWcucm4yIDwtIHBhcl90b19kZihwYXIgPSBjKDAuNzMxOTgyNzg0LAktMjEuNjk3OTk0NDksCTE0OS43ODQxODc2LAkxNy4wMjU1MTc2OSksIGN1ZV9yYW5nZSA9IHNlcSgwLCA2KigxMF42KSwgYnkgPSAoNiooMTBeNikpLzUwMDApKQoKIyBjb252ZXJ0IGxvZyB0byBub24tbG9nZ2VkIHNjYWxlCmdfbG9nLnJuJGN1ZV9yYW5nZSA8LSAxMF4oZ19sb2cucm4kY3VlX3JhbmdlKQpnX2xvZy5ybjIkY3VlX3JhbmdlIDwtIDEwXihnX2xvZy5ybjIkY3VlX3JhbmdlKQpJX0lnX2xvZy5ybiRjdWVfcmFuZ2UgPC0gMTBeKElfSWdfbG9nLnJuJGN1ZV9yYW5nZSkKSV9JZ19sb2cucm4yJGN1ZV9yYW5nZSA8LSAxMF4oSV9JZ19sb2cucm4yJGN1ZV9yYW5nZSkKCiMgZ2V0IHJ1ZwpnX2xvZy5ydWcgPC0gZGVmYXVsdC5zdGF0ZSAlPiUgCiAgZmlsdGVyKGxhYmVsX3NpID09ICJHIGxvZyIpICU+JSAKICBtdXRhdGUodmFsdWUgPSAxMF52YWx1ZSkgJT4lIAogIHNlbGVjdChsYWJlbF9zaSwgdmFsdWUpCgpnX2xvZy5ydWcyIDwtIG5vX1cuc3RhdGUgJT4lIAogIGZpbHRlcihsYWJlbF9zaSA9PSAiRyBsb2ciKSAlPiUgCiAgbXV0YXRlKHZhbHVlID0gMTBedmFsdWUpICU+JSAKICBmaWx0ZXIodmFsdWUgPD0gNiooMTBeNCkpICU+JSAKICBzZWxlY3QobGFiZWxfc2ksIHZhbHVlKQoKSV9JZ19sb2cucnVnIDwtIGRlZmF1bHQuc3RhdGUgJT4lIAogIGZpbHRlcihsYWJlbF9zaSA9PSAiSStJZyBsb2ciKSAlPiUgCiAgc2VsZWN0KGxhYmVsX3NpLCB2YWx1ZSkKCklfSWdfbG9nLnJ1ZzIgPC0gbm9fVy5zdGF0ZSAlPiUgCiAgZmlsdGVyKGxhYmVsX3NpID09ICJJK0lnIGxvZyIpICU+JSAKICBzZWxlY3QobGFiZWxfc2ksIHZhbHVlKQoKZy5ydWcgPC0gZGVmYXVsdC5zdGF0ZSAlPiUgCiAgZmlsdGVyKGxhYmVsX3NpID09ICJHIikgJT4lIAogIHNlbGVjdChsYWJlbF9zaSwgdmFsdWUpCgpnLnJ1ZzIgPC0gbm9fVy5zdGF0ZSAlPiUgCiAgZmlsdGVyKGxhYmVsX3NpID09ICJHIiAmIHZhbHVlIDw9IDYqKDEwXjQpKSAlPiUgCiAgc2VsZWN0KGxhYmVsX3NpLCB2YWx1ZSkKCklfSWcucnVnIDwtIGRlZmF1bHQuc3RhdGUgJT4lIAogIGZpbHRlcihsYWJlbF9zaSA9PSAiSStJZyIpICU+JSAKICBzZWxlY3QobGFiZWxfc2ksIHZhbHVlKQoKSV9JZy5ydWcyIDwtIG5vX1cuc3RhdGUgJT4lIAogIGZpbHRlcihsYWJlbF9zaSA9PSAiSStJZyIpICU+JSAKICBzZWxlY3QobGFiZWxfc2ksIHZhbHVlKQoKIyBnZXQgcnVnIGxpbWl0cwpydWdfbGltIDwtIHJiaW5kKGdfbG9nLnJ1ZywKICAgICAgICAgICAgICAgICBnX2xvZy5ydWcyLAogICAgICAgICAgICAgICAgIElfSWdfbG9nLnJ1ZywKICAgICAgICAgICAgICAgICBJX0lnX2xvZy5ydWcyLAogICAgICAgICAgICAgICAgIGcucnVnLAogICAgICAgICAgICAgICAgIGcucnVnMiwKICAgICAgICAgICAgICAgICBJX0lnLnJ1ZywKICAgICAgICAgICAgICAgICBJX0lnLnJ1ZzIpICU+JSAKICBncm91cF9ieShsYWJlbF9zaSkgJT4lIAogIHN1bW1hcml6ZShtYXggPSBtYXgoaGFibGFyOjpzKHZhbHVlKSwgbmEucm0gPSBUKSwKICAgICAgICAgICAgbWluID0gbWluKGhhYmxhcjo6cyh2YWx1ZSksIG5hLnJtID0gVCkpCgojIGNvbWJpbmUgYW5kIGZpbHRlcgpybiA8LSByYmluZCgKICBjYmluZChnX2xvZy5ybiwgbGFiZWxfc2kgPSAiRyBsb2ciLCBjb25kaXRpb24gPSAiRGVmYXVsdCIpLAogIGNiaW5kKGdfbG9nLnJuMiwgbGFiZWxfc2kgPSAiRyBsb2ciLCBjb25kaXRpb24gPSAiTm8gdGFyZ2V0ZWRcbmltbXVuaXR5IiksCiAgY2JpbmQoZy5ybiwgbGFiZWxfc2kgPSAiRyIsIGNvbmRpdGlvbiA9ICJEZWZhdWx0IiksCiAgY2JpbmQoZy5ybjIsIGxhYmVsX3NpID0gIkciLCBjb25kaXRpb24gPSAiTm8gdGFyZ2V0ZWRcbmltbXVuaXR5IiksCiAgY2JpbmQoSV9JZ19sb2cucm4sIGxhYmVsX3NpID0gIkkrSWcgbG9nIiwgY29uZGl0aW9uID0gIkRlZmF1bHQiKSwKICBjYmluZChJX0lnX2xvZy5ybjIsIGxhYmVsX3NpID0gIkkrSWcgbG9nIiwgY29uZGl0aW9uID0gIk5vIHRhcmdldGVkXG5pbW11bml0eSIpLAogIGNiaW5kKElfSWcucm4sIGxhYmVsX3NpID0gIkkrSWciLCBjb25kaXRpb24gPSAiRGVmYXVsdCIpLAogIGNiaW5kKElfSWcucm4yLCBsYWJlbF9zaSA9ICJJK0lnIiwgY29uZGl0aW9uID0gIk5vIHRhcmdldGVkXG5pbW11bml0eSIpCikgJT4lIAogIGxlZnRfam9pbihydWdfbGltLCBieSA9ICJsYWJlbF9zaSIpICU+JSAKICBncm91cF9ieShsYWJlbF9zaSkgJT4lIAogIGZpbHRlcihjdWVfcmFuZ2UgPD0gbWF4ICYgY3VlX3JhbmdlID49IG1pbikKCiMgY29tYmluZSBydWcKcnVnIDwtIHJiaW5kKGNiaW5kKGdfbG9nLnJ1ZywgY29uZGl0aW9uID0gIkRlZmF1bHQiKSwKICAgICAgICAgICAgIGNiaW5kKGdfbG9nLnJ1ZzIsIGNvbmRpdGlvbiA9ICJObyB0YXJnZXRlZFxuaW1tdW5pdHkiKSwKICAgICAgICAgICAgIGNiaW5kKGcucnVnLCBjb25kaXRpb24gPSAiRGVmYXVsdCIpLAogICAgICAgICAgICAgY2JpbmQoZy5ydWcyLCBjb25kaXRpb24gPSAiTm8gdGFyZ2V0ZWRcbmltbXVuaXR5IiksCiAgICAgICAgICAgICBjYmluZChJX0lnX2xvZy5ydWcsIGNvbmRpdGlvbiA9ICJEZWZhdWx0IiksCiAgICAgICAgICAgICBjYmluZChJX0lnX2xvZy5ydWcyLCBjb25kaXRpb24gPSAiTm8gdGFyZ2V0ZWRcbmltbXVuaXR5IiksCiAgICAgICAgICAgICBjYmluZChJX0lnLnJ1ZywgY29uZGl0aW9uID0gIkRlZmF1bHQiKSwKICAgICAgICAgICAgIGNiaW5kKElfSWcucnVnMiwgY29uZGl0aW9uID0gIk5vIHRhcmdldGVkXG5pbW11bml0eSIpKQoKIyBjb2JpbmUgd2l0aCBlemxhYmVsCnJuMiA8LSBybiAlPiUgbGVmdF9qb2luKGV6X2xhYmVsLCBieSA9ICJsYWJlbF9zaSIpCnJ1ZzIgPC0gcnVnICU+JSBsZWZ0X2pvaW4oZXpfbGFiZWwsIGJ5ID0gImxhYmVsX3NpIikKCiMgZmlsdGVyIHJ1ZwpkZWZhdWx0LnJ1ZyA8LSBydWcyICU+JSBmaWx0ZXIoY29uZGl0aW9uID09ICJEZWZhdWx0IikKbm8ucnVnIDwtIHJ1ZzIgJT4lIGZpbHRlcihjb25kaXRpb24gPT0gIk5vIHRhcmdldGVkXG5pbW11bml0eSIpCmBgYAoKIyBwbG90CmBgYHtyfQpnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBybjIsIGFlcyh4ID0gY3VlX3JhbmdlLCB5ID0gY3IsIGNvbG9yID0gY29uZGl0aW9uKSkgKwogIGdlb21fcnVnKGRhdGEgPSBkZWZhdWx0LnJ1ZywgYWVzKHggPSB2YWx1ZSwgY29sb3IgPSBjb25kaXRpb24pLCBzaWRlcyA9ICJiIikgKwogIGdlb21fcnVnKGRhdGEgPSBuby5ydWcsIGFlcyh4ID0gdmFsdWUsIGNvbG9yID0gY29uZGl0aW9uKSwgc2lkZXMgPSAidCIpICsKICBmYWNldF93cmFwKH5mY3RfcmVsZXZlbChlel9sYWJlbF9zaSwgYygiR2FtZXRvY3l0ZSBsb2cxMCIsICJHYW1ldG9jeXRlIiwgIkFzZXh1YWwmc2V4dWFsXG5pUkJDIGxvZzEwIiwgIkFzZXh1YWwmc2V4dWFsIGlSQkMiKSksIHNjYWxlcyA9ICJmcmVlX3giKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSkpICsKICB0aGVtZV9idygpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID1jKCJEZWZhdWx0IiA9ICIjNDU3NWI0IiwgIk5vIHRhcmdldGVkXG5pbW11bml0eSIgPSAiI2ZjOGQ1OSIpKSArCiAgeWxpbSgwLCAxLjEpICsKICBsYWJzKHggPSAiQ3VlIHJhbmdlIiwgeSA9ICJDb252ZXJzaW9uIHJhdGUiLCBjb2xvciA9ICJDb25kaXRpb24iKQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vcGFydGl0aW9uX3JuLnRpZmYiKSwgd2lkdGggPSA3LjUsIGhlaWdodCA9IDYpCmBgYAoKIyBnZXQgY29udmVyc2lvbiByYXRlIGxlZ2VuZApgYGB7cn0Kbm9XX2RlZmF1bHQuY3IgJT4lIGZpbHRlcihpZCA9PSAiR19sb2ciKSAlPiUgCmdncGxvdCgpICsKICBnZW9tX3Jhc3RlcihhZXMoeCA9IHRpbWUsIHkgPSBpZCwgZmlsbCA9IERlZmF1bHQpKSArCiAgeGxpbSgxLDIwKSArCiAgdGhlbWVfYncoKSArCiAgICBsYWJzKHggPSAiVGltZSAoZGF5cykiLAogICAgICAgICBmaWxsID0gIkNvbnZlcnNpb24gcmF0ZSIpICsKICB0aGVtZShheGlzLnRpdGxlLnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCksKSArCiAgICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhsaW0gPSBjKDAsIDEpKQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vY3JfbGVnZW5kLnRpZmYiKSkKYGBgCgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMgRGlzZWFzZSBjdXJ2ZXMgZm9yIHNpbmdsZSwgY28taW5mZWN0aW9uLCBhbmQgaW52YXNpb24KIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMgZ2V0IGRhdGEgZm9yIGRpc2Vhc2UgY3VydmVzCmBgYHtyfQojIHNpbmdsZSBpbmZlY3Rpb24gZHluYW1pY3MKc2lfZHluLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL3NpX2R5bi9zaV9keW5fMzAucGFycXVldCIpKSAKCiMgY28taW5mZWN0aW9uIGR5bmFtaWNzIChtb24tY3VlKQpjaV9keW4uZGYgPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvY2lfZHluL2NpX2R5bi5wYXJxdWV0IikpCgojIGR1YWwgY3VlIGR5bmFtaWNzCmR1YWxfZHluLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2R1YWxfY3VlX2R5bi9kdWFsX2N1ZV9keW4ucGFycXVldCIpKQpgYGAKCiMtLS0tLS0tIHNpbmdsZSBjdWUgY29tcGFyaXNvbiAtLS0tLS0tLS0tLS0tLS0jCiMgcHJvY2VzcyBkYXRhCmBgYHtyfQojIGdldCBjbGFzc2lmaWNhdGlvbgpzaV9jdWUuZHYgPC0gc2lfZml0bmVzcy5kZiAlPiUgCiAgbXV0YXRlKGNsYXNzaWZpY2F0aW9uID0gY2FzZV93aGVuKAogICAgdmFsdWUgPiA5LjIgfiAiSGlnaC1wZXJmb3JtaW5nIiwKICAgIHZhbHVlIDw9IDkuMiB+ICJQb29yLXBlcmZvcm1pbmciCiAgKSkKCiMgcHJvY2VzcyBkeW5hbWljcyAtPiB0dXJuIHNraW5ueQpzaV9kYy5kZiA8LSBzaV9keW4uZGYgJT4lIAogIGZpbHRlcih2YXJpYWJsZSA9PSAiSSIgfCB2YXJpYWJsZSA9PSAiSWciIHwgdmFyaWFibGUgPT0gIlIiKSAlPiUgCiAgdGlkeXI6OnBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSB2YXJpYWJsZSwgdmFsdWVzX2Zyb20gPSB2YWx1ZSkgJT4lIAogIG11dGF0ZSh0b3RhbCA9IEkrSWcpCgojIGpvaW4gd2l0aCBjbGFzc2lmaWNhaXRvbgpzaV9kYy5kZjIgPC0gc2lfZGMuZGYgJT4lIGxlZnRfam9pbihzZWxlY3Qoc2lfY3VlLmR2LCBpZCwgY2xhc3NpZmljYXRpb24pLCBieSA9ICJpZCIpCnNpX2N1ZS5kdgojIHNwbGl0IGludG8gdG9wIGVyZm9ybWluZyBhbmQgcG9vci1wZXJmb3JtaW5nIGN1ZXMKc2lfZGMuaGlnaCA8LSBzaV9kYy5kZjIgJT4lIGZpbHRlcihjbGFzc2lmaWNhdGlvbiA9PSAiSGlnaC1wZXJmb3JtaW5nIikKc2lfZGMucG9vciA8LSBzaV9kYy5kZjIgJT4lIGZpbHRlcihjbGFzc2lmaWNhdGlvbiA9PSAiUG9vci1wZXJmb3JtaW5nIikKCiMgam9pbiBoaWdoIHBlcmZvcm1pbmcgd2l0aCBsYWJlbApzaV9kYy5oaWdoIDwtIHNpX2RjLmhpZ2ggJT4lIGxlZnRfam9pbihlel9sYWJlbCAlPiUgZGlzdGluY3QobGFiZWxfc2ksIC5rZWVwX2FsbCA9IFQpLCBieSA9IGMoImlkIiA9ICJpZF9zaSIpKQoKI3dyaXRlX3BhcnF1ZXQoc2lfZGMuaGlnaCwgaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL3NpX2RjX2hpZ2gucGFycXVldCIpKQojd3JpdGVfcGFycXVldChzaV9kYy5wb29yLCBoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvc2lfZGNfcG9vci5wYXJxdWV0IikpCmBgYAoKIyBwbG90CmBgYHtyfQpzaV9kYy5wb29yIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvc2lfZGNfcG9vci5wYXJxdWV0IikpCnNpX2RjLmhpZ2ggPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9zaV9kY19oaWdoLnBhcnF1ZXQiKSkKCiMgcGxvdApzaV9kYy5wcmUgPC0gZ2dwbG90KCkgKwogIGdlb21fcGF0aChkYXRhID0gc2lfZGMucG9vciwgYWVzKHg9IHRvdGFsLCB5ID0gUiwgZ3JvdXAgPSBpZCksIGNvbG9yID0gImRhcmsgZ3JleSIsIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIGxhYnMoY29sb3IgPSAiU2luZ2xlIGluZmVjdGlvblxuZ29vZCBwZXJmb3JtaW5nIGN1ZXMiLCB4ID0gIkFzZXh1YWwgJiBzZXh1YWwgaVJCQyBwZXIgwrVMIiwgeSA9ICJSQkMgcGVyIMK1TCIpICsKICB0aGVtZV9idygpKyBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUUlVFLCBhY2N1cmFjeSA9IDAuMSkpICsKICBndWlkZXMoc2hhcGUgPSBGQUxTRSkKCnNpX2RjLnBsIDwtIHNpX2RjLnByZSArCiAgZ2VvbV9wb2ludChkYXRhID0gc2lfZGMuaGlnaCAlPiUgZmlsdGVyKHJvd19udW1iZXIoKSAlJSAxMDAwID09MCksIGFlcyh4ID0gdG90YWwsIHkgPSBSLCBjb2xvciA9IGV6X2xhYmVsLCBzaGFwZSA9IGV6X2xhYmVsKSwgc2l6ZSA9IDMpICsKICBnZW9tX3BhdGgoZGF0YSA9IHNpX2RjLmhpZ2gsIGFlcyh4PSB0b3RhbCwgeSA9IFIsIGdyb3VwID0gZXpfbGFiZWwsIGNvbG9yID0gZXpfbGFiZWwpLCBzaXplID0gMSwgYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCAiIzQ1NzViNCIsICIjZmM4ZDU5IiwgIiNmZGNiNDQiLCAiIzkxYmZkYiIpKSAgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSArCiAgZ3VpZGVzKGNvbG9yPWd1aWRlX2xlZ2VuZChucm93PTIsYnlyb3c9VFJVRSkpCmBgYAoKIy0tLS0tLS0tLS0gY28taW5mZWN0aW9uIG1vbm9jdWUgLS0tLS0tLS0tLS0tLSMKYGBge3J9CiMgZ2V0IHJlbGV2ZW50IHZhcmlhYmxlcwpjaV9kYy5kZiA8LSBjaV9keW4uZGYgJT4lIAogIGZpbHRlcih2YXJpYWJsZSA9PSAiSTEiIHwgdmFyaWFibGUgPT0gIklnMSIgfCB2YXJpYWJsZSA9PSAiUiIpCgojIG1vcnBoIGludG8gc2tpbm55IGZvcm1hdApjaV9kYy5kZiA8LSB0aWR5cjo6cGl2b3Rfd2lkZXIoY2lfZGMuZGYsIG5hbWVzX2Zyb20gPSB2YXJpYWJsZSwgdmFsdWVzX2Zyb20gPSB2YWx1ZSwgaWRfY29scyA9IGModGltZSwgbGFiZWwpKSAlPiUgCiAgbXV0YXRlKHRvdGFsID0gSTErSWcxKQoKIyBnb29kIGN1ZSBiYWQgY3VlCmNpX2N1ZS5kdiA8LSBjaV9maXRuZXNzLmRmICU+JSAKICBtdXRhdGUoY2xhc3NpZmljYXRpb24gPSBjYXNlX3doZW4oCiAgICB2YWx1ZSA+IDIuMjUgfiAiSGlnaC1wZXJmb3JtaW5nIiwKICAgIHZhbHVlIDw9IDIuMjUgfiAiUG9vci1wZXJmb3JtaW5nIgogICkpCgojIGpvaW4gd2l0aCBjbGFzc2lmaWNhaXRvbgpjaV9kYy5kZjIgPC0gY2lfZGMuZGYgJT4lIGxlZnRfam9pbihjaV9jdWUuZHYsIGJ5ID0gImxhYmVsIikKCiMgc3BsaXQgaW50byB0b3AgZXJmb3JtaW5nIGFuZCBwb29yLXBlcmZvcm1pbmcgY3VlcwpjaV9kYy5oaWdoIDwtIGNpX2RjLmRmMiAlPiUgZmlsdGVyKGNsYXNzaWZpY2F0aW9uID09ICJIaWdoLXBlcmZvcm1pbmciKQpjaV9kYy5wb29yIDwtIGNpX2RjLmRmMiAlPiUgZmlsdGVyKGNsYXNzaWZpY2F0aW9uID09ICJQb29yLXBlcmZvcm1pbmciKQoKIyBqb2luIGhpZ2ggcGVyZm9ybWluZyB3aXRoIGxhYmVsCmNpX2RjLmhpZ2gyIDwtIGNpX2RjLmhpZ2ggJT4lIGxlZnRfam9pbihlel9sYWJlbCwgYnkgPSBjKCJsYWJlbCIgPSAibGFiZWxfY2kiKSkKCiN3cml0ZV9wYXJxdWV0KGNpX2RjLmhpZ2gyLCBoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvY2lfZGNfaGlnaC5wYXJxdWV0IikpCiN3cml0ZV9wYXJxdWV0KGNpX2RjLnBvb3IsIGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9jaV9kY19wb29yLnBhcnF1ZXQiKSkKYGBgCgojIHBsb3QKYGBge3J9CmNpX2RjLnBvb3IgPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9jaV9kY19wb29yLnBhcnF1ZXQiKSkKY2lfZGMuaGlnaDIgPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9jaV9kY19oaWdoLnBhcnF1ZXQiKSkKCiMgcGxvdApjaV9kYy5wcmUgPC0gZ2dwbG90KCkgKwogIGdlb21fcGF0aChkYXRhID0gY2lfZGMucG9vciwgYWVzKHg9IHRvdGFsLCB5ID0gUiwgZ3JvdXAgPSBsYWJlbCksIGNvbG9yID0gImRhcmsgZ3JleSIsIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIGxhYnMoY29sb3IgPSAiQ28taW5mZWN0aW9uXG5nb29kIHBlcmZvcm1pbmcgY3VlcyIsIHggPSAiQXNleHVhbCAmIHNleHVhbCBpUkJDIHBlciDCtUwiLCB5ID0gIlJCQyBwZXIgwrVMIikgKwogIHRoZW1lX2J3KCkrIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFRSVUUsIGFjY3VyYWN5ID0gMC4xKSkgKwogIGd1aWRlcyhzaGFwZSA9IEZBTFNFKQoKY2lfZGMucGwgPC0gY2lfZGMucHJlICsKICBnZW9tX3BvaW50KGRhdGEgPSBjaV9kYy5oaWdoMiAlPiUgZmlsdGVyKHJvd19udW1iZXIoKSAlJSAxMDAwID09MCksIGFlcyh4ID0gdG90YWwsIHkgPSBSLCBjb2xvciA9IGV6X2xhYmVsLCBzaGFwZSA9IGV6X2xhYmVsKSwgc2l6ZSA9IDMpICsKICBnZW9tX3BhdGgoZGF0YSA9IGNpX2RjLmhpZ2gyLCBhZXMoeD0gdG90YWwsIHkgPSBSLCBncm91cCA9IGV6X2xhYmVsLCBjb2xvciA9IGV6X2xhYmVsKSwgc2l6ZSA9IDEsIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YyggIiM0NTc1YjQiLCAiI2ZjOGQ1OSIsICIjZmRjYjQ0IiwgIiM5MWJmZGIiKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSArCiAgZ3VpZGVzKGNvbG9yPWd1aWRlX2xlZ2VuZChucm93PTIsYnlyb3c9VFJVRSkpCgpgYGAKCiMtLS0tLS0tLS0gZHVhbCBjdWUgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0jCiMgcHJvY2VzcyBkYXRhCmBgYHtyfQojIHR1cm4gc2tpbm55CmR1YWxfZGMuZGYgPC0gZHVhbF9keW4uZGYgJT4lIAogIG11dGF0ZShsYWJlbF9hbHQgPSBwYXN0ZShsYWJlbCwgIisiICwgbGFiZWxfYikpICU+JSAKICBzZWxlY3QobGFiZWxfYWx0LCB0aW1lLCB2YXJpYWJsZSwgdmFsdWUpICU+JSAKICBmaWx0ZXIodmFyaWFibGUgPT0gIkkiIHwgdmFyaWFibGUgPT0gIklnIiB8IHZhcmlhYmxlID09ICJSIikgJT4lIAogIGRpc3RpbmN0KGxhYmVsX2FsdCwgdGltZSwgdmFyaWFibGUsIC5rZWVwX2FsbCA9IFQpCgpkdWFsX2R5bi5kZgoKZHVhbF9kYy5kZjIgPC0gZHVhbF9kYy5kZiAlPiUgCiAgdGlkeXI6OnBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSB2YXJpYWJsZSwgdmFsdWVzX2Zyb20gPSB2YWx1ZSwgaWRfY29scyA9IGModGltZSwgbGFiZWxfYWx0KSkgJT4lCiAgbXV0YXRlKHRvdGFsID0gSStJZykKCndyaXRlX3BhcnF1ZXQoZHVhbF9kYy5kZjIsIGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9kdWFsX2RjLnBhcnF1ZXQiKSkKCiMgZ29vZCBkdWFsIGN1ZSAtPiBsaXN0IG9mIGdvb2QgcGVyZm9ybWluZyBkdWFsIGN1ZXMgdGhhdCBlbmNvbXBhc3Mgd2lkZSB2YXJpZXR5IG9mIGN1ZXMKc2VsZWN0ZWRfZHVhbF9jdWUgPC0gYygiUiBsb2cgKyBJIGxvZyIsICJSICsgSWcgbG9nIiwgIkcgbG9nICsgSSBsb2ciLCAiRyBsb2cgKyBJZyBsb2ciLCAiSWcgKyBJIGxvZyIpCmJhZF9kdWFsX2N1ZSA8LSBjKCJHICsgSSIsICJSICsgSWciLCAiUiBsb2cgKyBJZyIsICJHICsgUiIsICJHICsgUiBsb2ciLCAiRyArIElnIiwgIklnICsgSSIsICJSICsgSSIsICJSIGxvZyArIEkiKQoKIyBnZXQgY2xhc3NpZmljYXRpb24gLT4gUiBsb2cxMCArIEkgbG9nMTAgYXMgdGhlIG9ubHkgZ29vZCBvbmUKZHVhbF9kYy5oaWdoIDwtIGR1YWxfZGMuZGYyICU+JSBmaWx0ZXIobGFiZWxfYWx0ICVpbiUgc2VsZWN0ZWRfZHVhbF9jdWUpICU+JSAKICBtdXRhdGUobGFiZWxfYWx0ID0gZ3N1YigibG9nIiwgImxvZzEwIiwgbGFiZWxfYWx0KSkKZHVhbF9kYy5wb29yIDwtIGR1YWxfZGMuZGYyICU+JSBmaWx0ZXIobGFiZWxfYWx0ICVpbiUgYmFkX2R1YWxfY3VlKSAlPiUgCiAgbXV0YXRlKGxhYmVsX2FsdCA9IGdzdWIoImxvZyIsICJsb2cxMCIsIGxhYmVsX2FsdCkpCiN3cml0ZV9wYXJxdWV0KGR1YWxfZGMuaGlnaCwgaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL2R1YWxfZGNfaGlnaC5wYXJxdWV0IikpCiN3cml0ZV9wYXJxdWV0KGR1YWxfZGMucG9vciwgaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL2R1YWxfZGNfcG9vci5wYXJxdWV0IikpCgpgYGAKCiMgcGxvdApgYGB7cn0KZHVhbF9kYy5oaWdoIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvZHVhbF9kY19oaWdoLnBhcnF1ZXQiKSkKZHVhbF9kYy5wb29yIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvZHVhbF9kY19wb29yLnBhcnF1ZXQiKSkKCmR1YWxfZGMuaGlnaDIgPC0gZHVhbF9kYy5oaWdoICU+JSAKICBmaWx0ZXIobGFiZWxfYWx0ID09ICJSIGxvZzEwICsgSSBsb2cxMCIpCgojIGFkZCAKZHVhbF9kYy5wcmUgPC0gZ2dwbG90KCkgKwogIGdlb21fcGF0aChkYXRhID0gZHVhbF9kYy5wb29yLCBhZXMoeD0gdG90YWwsIHkgPSBSLCBncm91cCA9IGxhYmVsX2FsdCksIGNvbG9yID0gImRhcmsgZ3JleSIsIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIGxhYnMoY29sb3IgPSAiSGlnaC1wZXJmb3JtaW5nXG5kdWFsIGN1ZXMgcGVyIMK1TCIsIHggPSAiQXNleHVhbCAmIHNleHVhbCBpUkJDIiwgeSA9ICJSQkMgcGVyIMK1TCIpICsKICB0aGVtZV9idygpKyBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUUlVFLCBhY2N1cmFjeSA9IDAuMSkpICsKICBndWlkZXMoc2hhcGUgPSBGQUxTRSkKCgpkdWFsX2RjLnBsIDwtIGR1YWxfZGMucHJlICsKICBnZW9tX3BvaW50KGRhdGEgPSBkdWFsX2RjLmhpZ2gyICU+JSBmaWx0ZXIocm93X251bWJlcigpICUlIDEwMDAgPT0wKSwgYWVzKHggPSB0b3RhbCwgeSA9IFIsIHNoYXBlID0gbGFiZWxfYWx0KSwgY29sb3IgPSAiIzQ1NzViNCIsIHNpemUgPSAzKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBkdWFsX2RjLmhpZ2gyLCBhZXMoeD0gdG90YWwsIHkgPSBSLCBncm91cCA9IGxhYmVsX2FsdCksIGNvbG9yID0gIiM0NTc1YjQiLCBzaXplID0gMSwgYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDAuMSkpKQpgYGAKCiMtLS0tLS0tLS0gY28taW5mZWN0aW9uIHN0YXRpYyAtLS0tLS0tLS0tLS0tLS0tIwpgYGB7cn0KIyBpbXBvcnQgaW4gZHluYW1pY3MgZGF0YQpzdGF0aWNfZHluLmxzIDwtIGxpc3QuZmlsZXMocGF0aCA9IGhlcmUoImRhdGEvY2lfc3RhdGljLyIpLCBwYXR0ZXJuID0gIioucGFycXVldCIsIGZ1bGwubmFtZXMgPSBUKQpzdGF0aWNfZHluLmxzIDwtIGxhcHBseShzdGF0aWNfZHluLmxzLCByZWFkX3BhcnF1ZXQpCgojIGZpbHRlciB2YXJpYWJsZSBhbmQgdHJhbnNmb3JtCnN0YXRpY19keW4ubHMyIDwtIG1jbGFwcGx5KHN0YXRpY19keW4ubHMsIGZ1bmN0aW9uKHgpewogIHggJT4lIAogICAgZmlsdGVyKHZhcmlhYmxlID09ICJJMSIgfCB2YXJpYWJsZSA9PSAiSWcxIiB8IHZhcmlhYmxlID09ICJJMiIgfCB2YXJpYWJsZSA9PSAiSWcyIiB8IHZhcmlhYmxlID09ICJSIikgJT4lIAogICAgbXV0YXRlKGlkX2FsdCA9IHBhc3RlKGlkXzEsIGlkXzIpKSAlPiUgCiAgICB0aWR5cjo6cGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHZhcmlhYmxlLCB2YWx1ZXNfZnJvbSA9IHZhbHVlLCBpZF9jb2xzID0gYyh0aW1lLCBpZF9hbHQpKSAlPiUKICBtdXRhdGUodG90YWwxID0gSTErSWcxLCB0b3RhbDIgPSBJMitJZzIpCn0pCgpzdGF0aWNfZGMuZGYgPC0gZG8uY2FsbChyYmluZCwgc3RhdGljX2R5bi5sczIpCnN0YXRpY19kYy5kZiA8LSBzdGF0aWNfZGMuZGYgJT4lIAogIG11dGF0ZShpZF8xID0gZ3N1YigiIC4qIiwgIiIsIGlkX2FsdCksCiAgICAgICAgIGlkXzIgPSBnc3ViKCIuKiAiLCAiIiwgaWRfYWx0KSkgJT4lIAogIGZpbHRlcihpZF8xICE9IGlkXzIpCiN3cml0ZV9wYXJxdWV0KHN0YXRpY19kYy5kZiwgaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL3N0YXRpY19kYy5wYXJxdWV0IikpCmBgYAoKIyBmdXJ0aGVyIHByb2Nlc3NpbmcKYGBge3J9CnN0YXRpY19kYy5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL3N0YXRpY19kYy5wYXJxdWV0IikpCiMgZ2V0IHdpbm5lcnMgYW5kIGxvc2VycwojIyBpbXBvcnQgaW4gZml0bmVzcwpzdGF0aWNfZml0bmVzcy5kZiA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2NpX3N0YXRpYy5jc3YiKSkKIyMgZ2V0IHdpbm5lciBzaXR1YXRpb24Kc3RhdGljX2ZpdG5lc3MuZGYyIDwtIHN0YXRpY19maXRuZXNzLmRmICU+JSAKICBmaWx0ZXIoaWRfMSAhPSBpZF8yKSAlPiUgCiAgbXV0YXRlKHdpbm5pbmdfaWQgPSBjYXNlX3doZW4oCiAgICBmaXRuZXNzX2RpZmZlcmVuY2UgPiAwIH4gaWRfMSwKICAgIGZpdG5lc3NfZGlmZmVyZW5jZTwgMCB+IGlkXzIKICApLAogIGxvc2luZ19pZCA9IGNhc2Vfd2hlbigKICAgIGZpdG5lc3NfZGlmZmVyZW5jZSA8IDAgfiBpZF8xLAogICAgZml0bmVzc19kaWZmZXJlbmNlPiAwIH4gaWRfMgogICkpCgojIGxlZnQgam9pbgpzdGF0aWNfZGMuZGYyIDwtIHN0YXRpY19kYy5kZiAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChzdGF0aWNfZml0bmVzcy5kZjIsIGlkXzEsIGlkXzIsIHdpbm5pbmdfaWQsIGxvc2luZ19pZCwgZml0bmVzc19kaWZmZXJlbmNlKSwgYnkgPSBjKCJpZF8xIiwgImlkXzIiKSkKCiMgZ2V0IHdpbm5lci1sb3NlciBkaWZmZXJlbmNlIGluIHRlcm1zIG9mIEkrSWcgYWxzbyBmaWx0ZXIgb3V0IHRvIG9ueWwgdmVyeSBzdHJvbmcgZml0bmVzcyBkaWZmZXJlbmNlCnN0YXRpY19kYy5kZjMgPC0gc3RhdGljX2RjLmRmMiAlPiUgCiAgbXV0YXRlKHRvdGFsX2RpZmYgPSBjYXNlX3doZW4oCiAgICBmaXRuZXNzX2RpZmZlcmVuY2UgPiAwIH4gdG90YWwxLXRvdGFsMiwKICAgIGZpdG5lc3NfZGlmZmVyZW5jZTwgMCB+IHRvdGFsMi10b3RhbDIKICApLAogIHRvdGFsX3dpbm5lciA9IGNhc2Vfd2hlbigKICAgIGZpdG5lc3NfZGlmZmVyZW5jZSA+IDAgfiB0b3RhbDEsCiAgICBmaXRuZXNzX2RpZmZlcmVuY2U8IDAgfiB0b3RhbDIKICApLAogIHRvdGFsX2xvc2VyID0gY2FzZV93aGVuKAogICAgZml0bmVzc19kaWZmZXJlbmNlID4gMCB+IHRvdGFsMiwKICAgIGZpdG5lc3NfZGlmZmVyZW5jZTwgMCB+IHRvdGFsMQogICkpICU+JSAKICBmaWx0ZXIoYWJzKGZpdG5lc3NfZGlmZmVyZW5jZSkgPiAwLjUpCmBgYAoKIyBwbG90CmBgYHtyfQpzdGF0aWNfZGMucGwgPC0gZ2dwbG90KCkgKwogIGdlb21fcGF0aChkYXRhID0gc3RhdGljX2RjLmRmMywgYWVzKHg9IHRvdGFsX3dpbm5lciwgeSA9IFIsIGdyb3VwID0gaWRfYWx0LCBjb2xvciA9ICJXaW5uZXIiKSwgYWxwaGEgPSAwLjUsIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIGdlb21fcGF0aChkYXRhID0gc3RhdGljX2RjLmRmMywgYWVzKHg9IHRvdGFsX2xvc2VyLCB5ID0gUiwgZ3JvdXAgPSBpZF9hbHQsIGNvbG9yID0gIkxvc2VyIiksCiAgICAgICAgICBhbHBoYSA9IDAuNSxhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICBsYWJzKGNvbG9yID0gIlN0YXR1cyIsIHggPSAiQXNleHVhbCAmIHNleHVhbCBpUkJDIiwgeSA9ICJSQkMiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJXaW5uZXIiID0gIiM0NTc1YjQiLCJMb3NlciI9ICIjZmM4ZDU5IikpICArCiAgdGhlbWVfYncoKSArIAogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFRSVUUsIGFjY3VyYWN5ID0gMC4xKSkKYGBgCgoKIy0tLS0tLS0tLWNvLWluZmVjdGlvbiBpbnZhc2lvbiAtLS0tLS0tLS0tLS0tLS0jCiMgZ2V0IGludmFzaW9uIGR5bmFtaWMKYGBge3J9CiMgZ2V0IGludmFzaW9uIGRmCmludmFzaW9uX2ZpdG5lc3MuZGYgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9jaV9pbnZhc2lvbi5jc3YiKSkKCiMgZ2V0IGN1ZSByYW5nZQpjaV9jdWVfcmFuZ2UgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9jdWVfcmFuZ2VfY2kuY3N2IikpCmludmFzaW9uX2ZpdG5lc3MuZGYyIDwtIGludmFzaW9uX2ZpdG5lc3MuZGYgJT4lIAogIGxlZnRfam9pbihzZWxlY3QoY2lfY3VlX3JhbmdlLCBpZCwgbXV0X2N1ZSA9IGN1ZSwgbXV0X2xvdyA9IGxvdywgbXV0X2hpZ2ggPSBoaWdoLCBtdXRfYnkgPSBieSksIGJ5ID0gYygibXV0X2lkIj0gImlkIikpICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGNpX2N1ZV9yYW5nZSwgaWQsIHJlc19jdWUgPSBjdWUsIHJlc19sb3cgPSBsb3csIHJlc19oaWdoID0gaGlnaCwgcmVzX2J5ID0gYnkpLCBieSA9IGMoInJlc19pZCI9ICJpZCIpKQpgYGAKCiMgZnVuY3Rpb24gdG8gZ2V0IGR5bmFtaWMKYGBge3J9CmdldF9pbnZhc2lvbl9keW4gPC0gZnVuY3Rpb24oZGYpewogICMgZ2V0IGN1ZXMKICBtdXRfY3VlIDwtIGRmJG11dF9jdWUKICByZXNfY3VlIDwtIGRmJHJlc19jdWUKICAKICAjIGdldCBpbmZvIG9mIGN1ZXMgKGZvciBjbyBpbmZlY3Rpb24pCiAgaWYoc3RyaW5ncjo6c3RyX2RldGVjdChtdXRfY3VlLCAiLWkiKSl7bXV0X2N1ZSA9IGdzdWIoIiotaSIsICIxIiwgbXV0X2N1ZSl9CiAgaWYoc3RyaW5ncjo6c3RyX2RldGVjdChtdXRfY3VlLCAiLWkiLCBuZWdhdGUgPSBUKSl7bXV0X2N1ZSA9IG11dF9jdWV9CiAgaWYoc3RyaW5ncjo6c3RyX2RldGVjdChyZXNfY3VlLCAiLWkiKSl7cmVzX2N1ZSA9IGdzdWIoIiotaSIsICIyIiwgcmVzX2N1ZSl9CiAgaWYoc3RyaW5ncjo6c3RyX2RldGVjdChyZXNfY3VlLCAiLWkiLCBuZWdhdGUgPSBUKSl7cmVzX2N1ZSA9IHJlc19jdWV9CiAgCiAgIyBnZXQgbG9nCiAgbXV0X2xvZyA8LSBpZmVsc2Uoc3RyaW5ncjo6c3RyX2RldGVjdChkZiRtdXRfaWQsICJsb2ciKSwgImxvZzEwIiwgIm5vbmUiKQogIHJlc19sb2cgPC0gaWZlbHNlKHN0cmluZ3I6OnN0cl9kZXRlY3QoZGYkcmVzX2lkLCAibG9nIiksICJsb2cxMCIsICJub25lIikKICAKICAjIGdldCBwYXJhbWV0ZXJzCiAgbXV0X3BhciA8LSBjKGRmJG11dF92YXIxX29wdCwgZGYkbXV0X3ZhcjJfb3B0LCBkZiRtdXRfdmFyM19vcHQsIGRmJG11dF92YXI0X29wdCkKICByZXNfcGFyIDwtIGMoZGYkcmVzX3ZhcjEsIGRmJHJlc192YXIyLCBkZiRyZXNfdmFyMywgZGYkcmVzX3ZhcjQpCiAgCiAgIyBnZXQgY3VlIHJhbmdlCiAgbXV0X2N1ZV9yYW5nZSA8LSBzZXEoZGYkbXV0X2xvdywgZGYkbXV0X2hpZ2gsIGJ5ID0gZGYkbXV0X2J5KQogIHJlc19jdWVfcmFuZ2UgPC0gc2VxKGRmJHJlc19sb3csIGRmJHJlc19oaWdoLCBieSA9IGRmJHJlc19ieSkKICAKICAjIGdldCBkeW5hbWljcyBvZiBjbyBpbmZlY3Rpb24KICBjaV9keW4gPC0gY2hhYmF1ZGlfY2lfY2xlYW4oCiAgICBwYXJhbWV0ZXJzX2NyXzEgPSBtdXRfcGFyLAogICAgcGFyYW1ldGVyc19jcl8yID0gcmVzX3BhciwKICAgICAgICAgICAgICAgICAgaW1tdW5pdHkgPSAidHN1a3VzaGkiLAogICAgICAgICAgICAgICAgICBwYXJhbWV0ZXJzID0gcGFyYW1ldGVyc190c3VrdXNoaSwKICAgICAgICAgICAgICAgICAgY3VlXzEgPSBtdXRfY3VlLAogICAgICAgICAgICAgICAgICBjdWVfMiA9IHJlc19jdWUsCiAgICAgICAgICAgICAgICAgIGN1ZV9yYW5nZV8xID0gbXV0X2N1ZV9yYW5nZSwKICAgICAgICAgICAgICAgICBjdWVfcmFuZ2VfMiA9IHJlc19jdWVfcmFuZ2UsCiAgICAgICAgICAgICAgICBsb2dfY3VlXzEgPSBtdXRfbG9nLAogICAgICAgICAgICAgICAgbG9nX2N1ZV8yID0gcmVzX2xvZywKICAgICAgICAgICAgICAgIHNvbHZlciA9ICJ2b2RlIiwKICAgICAgICAgICAgICAgIHRpbWVfcmFuZ2UgPSBzZXEoMCwgMzAsIDAuMDAxKSwKICAgIGR5biA9IFQpCiAgCiAgIyBhcHBlbmQgbGFiZWwgdG8gYWxsIGRmCiBjaV9keW4yIDwtIGNiaW5kKGNpX2R5biwgbXV0X2lkID0gZGYkbXV0X2lkLCByZXNfaWQgPSBkZiRyZXNfaWQpCiAgCiAgIyB3cml0ZQogd3JpdGVfcGFycXVldChjaV9keW4yLCBwYXN0ZTAoaGVyZSgiZGF0YS9jaV9pbnZhc2lvbl9keW4vIiksIGRmJG11dF9pZCwgIi0iLCBkZiRyZXNfaWQsICIucGFycXVldCIpKQp9CmBgYAoKCiMgcnVuIGR5bmFtaWMgZnVuY2l0b24KYGBge3J9CiMgZ2V0IGZ1bmN0aW9uIGFuZCBwYXJhbWV0ZXJzCnNvdXJjZShoZXJlKCJmdW5jdGlvbnMvY2hhYmF1ZGlfY2lfY2xlYW4uUiIpKQpwYXJhbWV0ZXJzX3RzdWt1c2hpIDwtIGMoUjEgPSA4Ljg5KigxMF42KSwgIyBzbGlnaHRseSBoaWdoZXIKICAgICAgICAgICAgICAgIGxhbWJkYSA9IDMuNyooMTBeNSksCiAgICAgICAgICAgICAgICBtdSA9IDAuMDI1LCAKICAgICAgICAgICAgICAgIHAgPSA4KigxMF4tNiksICMgZG91YmxlZCBmb3JtIG9yaWdpbmFsCiAgICAgICAgICAgICAgICBhbHBoYSA9IDEsIAogICAgICAgICAgICAgICAgYWxwaGFnID0gMiwgCiAgICAgICAgICAgICAgICBiZXRhID0gNS43MjEsIAogICAgICAgICAgICAgICAgbXVtID0gNDgsIAogICAgICAgICAgICAgICAgbXVnID0gNCwgCiAgICAgICAgICAgICAgICBJMCA9IDQzLjg1OTY1LCAKICAgICAgICAgICAgICAgIElnMCA9IDAsIAogICAgICAgICAgICAgICAgYSA9IDE1MCwgCiAgICAgICAgICAgICAgICBiID0gMTAwLCAKICAgICAgICAgICAgICAgIHNwID0gMSwKICAgICAgICAgICAgICAgIHBzaW4gPSAxNi42OTIzNCwKICAgICAgICAgICAgICAgIHBzaXcgPSAwLjg0MzE3ODUsCiAgICAgICAgICAgICAgICBwaGluID0gMC4wMzUyMDU5MSwgCiAgICAgICAgICAgICAgICBwaGl3ID0gNTUwLjg0MiwKICAgICAgICAgICAgICAgIGlvdGEgPSAyLjE4KigxMF42KSwKICAgICAgICAgICAgICAgIHJobyA9IDAuMjYyNzE1NikKIyBzcGxpdAppbnZhc2lvbi5scyA8LSBzcGxpdChpbnZhc2lvbl9maXRuZXNzLmRmMiwgc2VxKG5yb3coaW52YXNpb25fZml0bmVzcy5kZjIpKSkKCiMgcnVuIGZ1bmN0aW9uCm1jbGFwcGx5KGludmFzaW9uLmxzLCBnZXRfaW52YXNpb25fZHluLCBtYy5jb3JlcyA9IDQpCmBgYAoKCiMgcHJvY2VzcyBkYXRhCmBgYHtyfQojIGltcG9ydCBpbiBpbnZhc2lvbiBkeW5hbWljcwppbnZhc2lvbl9keW4ubHMgPC0gbGlzdC5maWxlcyhwYXRoID0gaGVyZSgiZGF0YS9jaV9pbnZhc2lvbl9keW4iKSwgcGF0dGVybiA9ICIqLnBhcnF1ZXQiLCBmdWxsLm5hbWVzID0gVCkKaW52YXNpb25fZHluLmxzIDwtIGxhcHBseShpbnZhc2lvbl9keW4ubHMsIHJlYWRfcGFycXVldCkKCiMgZmlsdGVyIGFuZCBzbyBvbgppbnZhc2lvbl9keW4ubHMyIDwtIG1jbGFwcGx5KGludmFzaW9uX2R5bi5sc1sxNjc6MTc3XSwgbWMuY29yZXMgPSA0LCBmdW5jdGlvbih4KXsKICB4MiA8LSB4ICU+JSAKICAgIGZpbHRlcih2YXJpYWJsZSA9PSAiSTEiIHwgdmFyaWFibGUgPT0gIklnMSIgfCB2YXJpYWJsZSA9PSAiSTIiIHwgdmFyaWFibGUgPT0gIklnMiIgfCB2YXJpYWJsZSA9PSAiUiIpICU+JSAKICAgIG11dGF0ZShpZF9hbHQgPSBwYXN0ZShtdXRfaWQsIHJlc19pZCkpICU+JSAKICAgIHNlbGVjdChpZF9hbHQsIHRpbWUsIHZhcmlhYmxlLCB2YWx1ZSkgJT4lIAogICAgdGlkeXI6OnBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSB2YXJpYWJsZSwgdmFsdWVzX2Zyb20gPSB2YWx1ZSwgaWRfY29scyA9IGModGltZSwgaWRfYWx0KSkgJT4lCiAgbXV0YXRlKHRvdGFsMSA9IEkxK0lnMSwgdG90YWwyID0gSTIrSWcyKQogIAogIHdyaXRlX3BhcnF1ZXQoeDIsIHBhc3RlMChoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvY2lfaW52YXNpb24vIiksIHVuaXF1ZSh4MiRpZF9hbHQpLCAiX2RjLnBhcnF1ZXQiKSkKfSkKCiMgZmV0Y2ggZGF0YQppbnZhc2lvbl9keW4ubHMyIDwtIGxpc3QuZmlsZXMocGF0aCA9IGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9jaV9pbnZhc2lvbiIpLCBwYXR0ZXJuID0gIioucGFycXVldCIsIGZ1bGwubmFtZXMgPSBUKQppbnZhc2lvbl9keW4ubHMyIDwtIGxhcHBseShpbnZhc2lvbl9keW4ubHMyLCByZWFkX3BhcnF1ZXQpCmludmFzaW9uX2RjLmRmIDwtIGRvLmNhbGwocmJpbmQsIGludmFzaW9uX2R5bi5sczIpCmludmFzaW9uX2RjLmRmIDwtIGludmFzaW9uX2RjLmRmICU+JSAKICBtdXRhdGUobXV0X2lkID0gZ3N1YigiIC4qIiwgIiIsIGlkX2FsdCksCiAgICAgICAgIHJlc19pZCA9IGdzdWIoIi4qICIsICIiLCBpZF9hbHQpKSAlPiUgCiAgZmlsdGVyKG11dF9pZCAhPSByZXNfaWQpCiN3cml0ZV9wYXJxdWV0KGludmFzaW9uX2RjLmRmLCBoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvaW52YXNpb25fZGMucGFycXVldCIpKQpgYGAKCiMgZnVydGhlciBwcm9jZXNzaW5nCmBgYHtyfQppbnZhc2lvbl9kYy5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL2ludmFzaW9uX2RjLnBhcnF1ZXQiKSkKIyBnZXQgd2lubmVycyBhbmQgbG9zZXJzCmludmFzaW9uX2ZpdG5lc3MuZGYgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9jaV9pbnZhc2lvbi5jc3YiKSkKaW52YXNpb25fZGMuZGYyIDwtIGludmFzaW9uX2RjLmRmICU+JSAKICBsZWZ0X2pvaW4oaW52YXNpb25fZml0bmVzcy5kZiwgYnkgPSBjKCJtdXRfaWQiLCAicmVzX2lkIikpICU+JSAKICBtdXRhdGUoCiAgdG90YWxfd2lubmVyID0gY2FzZV93aGVuKAogICAgZml0bmVzcz4gMCB+IHRvdGFsMSwKICAgIGZpdG5lc3M8IDAgfiB0b3RhbDIKICApLAogIHRvdGFsX2xvc2VyID0gY2FzZV93aGVuKAogICAgZml0bmVzcyA+IDAgfiB0b3RhbDIsCiAgICBmaXRuZXNzIDwgMCB+IHRvdGFsMQogICkpICU+JSAKICBmaWx0ZXIoYWJzKGZpdG5lc3MpID4gMC41KQpgYGAKCiMgcGxvdApgYGB7cn0KaW52YXNpb25fZGMucGwgPC0gZ2dwbG90KCkgKwogIGdlb21fcGF0aChkYXRhID0gaW52YXNpb25fZGMuZGYyLCBhZXMoeD0gdG90YWxfd2lubmVyLCB5ID0gUiwgZ3JvdXAgPSBpZF9hbHQsIGNvbG9yID0gIldpbm5lciIpLCBhbHBoYSA9IDAuNSwgYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBpbnZhc2lvbl9kYy5kZjIsIGFlcyh4PSB0b3RhbF9sb3NlciwgeSA9IFIsIGdyb3VwID0gaWRfYWx0LCBjb2xvciA9ICJMb3NlciIpLAogICAgICAgICAgYWxwaGEgPSAwLjUsYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgbGFicyhjb2xvciA9ICJTdGF0dXMiLCB4ID0gIkFzZXh1YWwgJiBzZXh1YWwgaVJCQyIsIHkgPSAiUkJDIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiV2lubmVyIiA9ICIjNDU3NWI0IiwiTG9zZXIiPSAiI2ZjOGQ1OSIpKSAgKwogIHRoZW1lX2J3KCkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUUlVFLCBhY2N1cmFjeSA9IDAuMSkpICU+JSAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKCiMtLS0tLS0tLS0gcXVhbnRpZnlpbmcgZGlzZWFzZSBjdXJ2ZSBhcmVhIC0tLS0tLS0tLS0tLSMKIyBmdW5jdGlvbiB0byBjYWxjdWxhdGUgYXJlYSBiZXR3ZWVuIHNldHMgb2YgcG9pbnRzIC0+IGZyb20gaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMzY3MjI2MC9hcmVhLWNvdmVyZWQtYnktYS1wb2ludC1jbG91ZC13aXRoLXIKYGBge3J9CmxpYnJhcnkoc3BsYW5jcykKY2hhPC1mdW5jdGlvbihkZil7CiAgeCA8LSBkZiR0b3RhbAogIHkgPC0gZGYkUgpjaHVsbCh4LHkpLT5pCnJldHVybihhcmVhcGwoY2JpbmQoeFtpXSx5W2ldKSkpCn0KYGBgCgojIGxvb3AgdG8gZ2V0IGFyZWE6IHNpbmdsZSBpbmZlY3Rpb24KYGBge3J9CiMgc3BsaXQgZGYKc2lfZGNfaGlnaC5scyA8LSBzcGxpdChzaV9kYy5oaWdoLCBzaV9kYy5oaWdoJGV6X2xhYmVsX3NpKQpzaV9kY19wb29yLmxzIDwtIHNwbGl0KHNpX2RjLnBvb3IsIHNpX2RjLnBvb3IkaWQpCgojIGdldCBhcmVhCnNpX2RjX2hpZ2guYXJlYSA8LSBjYmluZC5kYXRhLmZyYW1lKGFyZWEgPSBhcy5udW1lcmljKGxhcHBseShzaV9kY19oaWdoLmxzLCBjaGEpKSwgaWRfYWx0ID0gbmFtZXMobGFwcGx5KHNpX2RjX2hpZ2gubHMsIGNoYSkpKQpzaV9kY19wb29yLmFyZWEgPC0gY2JpbmQuZGF0YS5mcmFtZShhcmVhID0gYXMubnVtZXJpYyhsYXBwbHkoc2lfZGNfcG9vci5scywgY2hhKSksIGlkX2FsdCA9IG5hbWVzKGxhcHBseShzaV9kY19wb29yLmxzLCBjaGEpKSkKCgojIGpvaW4gd2l0aCBmaXRuZXNzCnNpX2ZpdG5lc3MuZGYgPC0gc2lfZml0bmVzcy5kZiAlPiUgbGVmdF9qb2luKGV6X2xhYmVsLCBieSA9IGMoImlkIiA9ICJpZF9zaSIpKQoKc2lfZGNfaGlnaC5hcmVhMiA8LSBzaV9kY19oaWdoLmFyZWEgJT4lIAogIGxlZnRfam9pbihzaV9maXRuZXNzLmRmLCBieSA9IGMoImlkX2FsdCIgPSAiZXpfbGFiZWxfc2kiKSkgJT4lIAogIHNlbGVjdCh2YWx1ZSwgYXJlYSkgJT4lIAogIG11dGF0ZShjb25kaXRpb24gPSAiU2luZ2xlIGluZmVjdGlvbiIpCgpzaV9kY19wb29yLmFyZWEyIDwtIHNpX2RjX3Bvb3IuYXJlYSAlPiUgCiAgbGVmdF9qb2luKHNpX2ZpdG5lc3MuZGYsIGJ5ID0gYygiaWRfYWx0IiA9ICJpZCIpKSAlPiUgCiAgc2VsZWN0KHZhbHVlLCBhcmVhKSAlPiUgCiAgbXV0YXRlKGNvbmRpdGlvbiA9ICJTaW5nbGUgaW5mZWN0aW9uIikKYGBgCgojIGNvaW5mZWN0aW9uCmBgYHtyfQojIHNwbGl0CmNpX2RjX2hpZ2gubHMgPC0gc3BsaXQoY2lfZGMuaGlnaDIsIGNpX2RjLmhpZ2gyJGV6X2xhYmVsKQpjaV9kY19wb29yLmxzIDwtIHNwbGl0KGNpX2RjLnBvb3IsIGNpX2RjLnBvb3IkbGFiZWwpCgojIHJ1biBmdW5jdGlvbiB0byBmaW5kIGFyZWEKY2lfZGNfaGlnaC5hcmVhIDwtIGNiaW5kLmRhdGEuZnJhbWUoYXJlYSA9IGFzLm51bWVyaWMobGFwcGx5KGNpX2RjX2hpZ2gubHMsIGNoYSkpLCBpZF9hbHQgPSBuYW1lcyhsYXBwbHkoY2lfZGNfaGlnaC5scywgY2hhKSksIHZhbHVlID0gdW5pcXVlKGNpX2RjLmhpZ2gyJHZhbHVlKSkKCmNpX2RjX3Bvb3IuYXJlYSA8LSBjYmluZC5kYXRhLmZyYW1lKGFyZWEgPSBhcy5udW1lcmljKGxhcHBseShjaV9kY19wb29yLmxzLCBjaGEpKSwgaWRfYWx0ID0gbmFtZXMobGFwcGx5KGNpX2RjX3Bvb3IubHMsIGNoYSkpLCB2YWx1ZSA9IHVuaXF1ZShjaV9kYy5wb29yJHZhbHVlKSkKCiMgZWRpdCBhbmQgam9pbgpjaV9kY19oaWdoLmFyZWEyIDwtICBjaV9kY19oaWdoLmFyZWEgJT4lIAogIHNlbGVjdChhcmVhLCB2YWx1ZSkgJT4lIAogIG11dGF0ZShjb25kaXRpb24gPSAiQ28taW5mZWN0aW9uIikKCmNpX2RjX3Bvb3IuYXJlYTIgPC0gIGNpX2RjX3Bvb3IuYXJlYSAlPiUgCiAgc2VsZWN0KGFyZWEsIHZhbHVlKSAlPiUgCiAgbXV0YXRlKGNvbmRpdGlvbiA9ICJDby1pbmZlY3Rpb24iKQpgYGAKCiMgZHVhbCBjdWUKYGBge3J9CiMgc3BsaXQKZHVhbC5kYyA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL2R1YWxfZGMucGFycXVldCIpKQpkdWFsX2RjLmxzIDwtIHNwbGl0KGR1YWwuZGMsIGR1YWwuZGMkbGFiZWxfYWx0KQoKIyBnZXQgYXJlYQpkdWFsX2RjLmFyZWEgPC0gY2JpbmQuZGF0YS5mcmFtZShhcmVhID0gYXMubnVtZXJpYyhsYXBwbHkoZHVhbF9kYy5scywgY2hhKSksIGlkX2FsdCA9IG5hbWVzKGxhcHBseShkdWFsX2RjLmxzLCBjaGEpKSkKCiMgYmluZCB3aXRoIGZpdG5lc3MKZHVhbF9maXRuZXNzLmRmIDwtIGR1YWxfZml0bmVzcy5kZiAlPiUgbXV0YXRlKGlkX2FsdCA9IHBhc3RlKGxhYmVsLCAiKyIsIGxhYmVsX2IpKQpkdWFsX2RjLmFyZWEyIDwtIGR1YWxfZGMuYXJlYSAlPiUgCiAgbGVmdF9qb2luKGR1YWxfZml0bmVzcy5kZiwgYnkgPSAiaWRfYWx0IikgJT4lIAogIHNlbGVjdChhcmVhLCB2YWx1ZSkgJT4lIAogIG11dGF0ZShjb25kaXRpb24gPSAiRHVhbC1jdWUiKSAlPiUgCiAgZmlsdGVyKHZhbHVlID4gMikKZHVhbF9kYy5hcmVhMgpgYGAKCiMtLS0tLS0gZ2V0IGZpdHRlZCBzY2F0dGVyIHBsb3QgZm9yIGFsbCBzaW5nbGUgaW5mZWN0aW9uLCBjbyBpbmZlY3Rpb24sIGFuZCBkdWFsIGN1ZSAtLS0tLS0tLSMKYGBge3J9CiMgcmJpbmQKc2kuYXJlYSA8LSByYmluZChzaV9kY19oaWdoLmFyZWEyLCBzaV9kY19wb29yLmFyZWEyKQpjaS5hcmVhIDwtIHJiaW5kKGNpX2RjX2hpZ2guYXJlYTIsIGNpX2RjX3Bvb3IuYXJlYTIpCmR1YWwuYXJlYSA8LSBkdWFsX2RjLmFyZWEyCgojIHBsb3QKbGlicmFyeSgiZ2dwbWlzYyIpCgpzaV9hcmVhLnBsIDwtIGdncGxvdChkYXRhID0gc2kuYXJlYSwgYWVzKHggPSBhcmVhLCB5ID0gdmFsdWUpKSArCiAgZ2VvbV9wb2ludCgpICsKICBzdGF0X3BvbHlfbGluZShjb2xvciA9ICJibGFjayIpICsKICBzdGF0X3BvbHlfZXEoKSArCiAgbGFicyh4ID0gIkFyZWEiLCB5ID0gIkZpdG5lc3MiLCBjb2xvciA9ICJTdGF0dXMiKSArCiAgdGhlbWVfYncoKQoKY2lfYXJlYS5wbCA8LSBnZ3Bsb3QoZGF0YSA9IGNpLmFyZWEsIGFlcyh4ID0gYXJlYSwgeSA9IHZhbHVlKSkgKwogIGdlb21fcG9pbnQoKSArCiAgc3RhdF9wb2x5X2xpbmUoY29sb3IgPSAiYmxhY2siKSArCiAgc3RhdF9wb2x5X2VxKCkgKwogIGxhYnMoeCA9ICJBcmVhIiwgeSA9ICJGaXRuZXNzIiwgY29sb3IgPSAiU3RhdHVzIikgKwogIHRoZW1lX2J3KCkKCmR1YWxfYXJlYS5wbCA8LSBnZ3Bsb3QoZGF0YSA9IGR1YWwuYXJlYSwgYWVzKHggPSBhcmVhLCB5ID0gdmFsdWUpKSArCiAgZ2VvbV9wb2ludCgpICsKICBzdGF0X3BvbHlfbGluZShjb2xvcj0gImJsYWNrIikgKwogIHN0YXRfcG9seV9lcSgpICsKICBsYWJzKHggPSAiQXJlYSIsIHkgPSAiRml0bmVzcyIsIGNvbG9yID0gIlN0YXR1cyIpICsKICB0aGVtZV9idygpCmBgYAoKCiMtLS0tLS0tIHBsb3QgdG9nZXRoZXIgd2l0aCBkaXNlYXNlIGN1cnZlIC0tLS0tLS0tIwpgYGB7cn0KIyBzaW5nbGUgaW5mZWN0aW9uCnNpX3Zpci5wbCA8LSBnZ2FycmFuZ2Uoc2lfZGMucGwsIHNpX2FyZWEucGwsIGFsaWduID0gInYiLCB3aWR0aHMgPSBjKDEsIDAuNDUpKQoKIyBjby1pbmZlY3Rpb24KY2lfdmlyLnBsIDwtIGdnYXJyYW5nZShjaV9kYy5wbCwgY2lfYXJlYS5wbCwgYWxpZ24gPSAidiIsIHdpZHRocyA9IGMoMSwgMC40NSkpCgojIGR1YWwtY3VlCmR1YWxfdmlyLnBsIDwtIGdnYXJyYW5nZShkdWFsX2RjLnBsLCBkdWFsX2FyZWEucGwsIGFsaWduID0gInYiLCB3aWR0aHMgPSBjKDEsIDAuNDUpKQpgYGAKCgojLS0tLS0tLS0tIHN0YXRpYyBhcmVhIGNvbXBhcmlzb24gLS0tLS0tLS0tLS0tLSMKIyBjb21wdXRlIGFyZWEKYGBge3J9CiMgaW1wb3J0IGluIGRjIGR5bmFtaWMgYW5kIGZpdG5lc3MKc3RhdGljX2RjLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvc3RhdGljX2RjLnBhcnF1ZXQiKSkKc3RhdGljX2ZpdG5lc3MuZGYgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9jaV9zdGF0aWMuY3N2IikpCgojIGdldCB3aW5uZXIgYW5kIGxvc2VyCnN0YXRpY19kYy5kZjQgPC0gc3RhdGljX2RjLmRmICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KHN0YXRpY19maXRuZXNzLmRmLCBpZF8xLCBpZF8yLCBmaXRuZXNzX2RpZmZlcmVuY2UpLCBieSA9IGMoImlkXzEiLCAiaWRfMiIpKSAlPiUKICBmaWx0ZXIoaWRfMSAhPSBpZF8yKSAlPiUgCiAgbXV0YXRlKAogIHRvdGFsX3dpbm5lciA9IGNhc2Vfd2hlbigKICAgIGZpdG5lc3NfZGlmZmVyZW5jZSA+IDAgfiB0b3RhbDEsCiAgICBmaXRuZXNzX2RpZmZlcmVuY2U8IDAgfiB0b3RhbDIKICApLAogIHRvdGFsX2xvc2VyID0gY2FzZV93aGVuKAogICAgZml0bmVzc19kaWZmZXJlbmNlID4gMCB+IHRvdGFsMiwKICAgIGZpdG5lc3NfZGlmZmVyZW5jZTwgMCB+IHRvdGFsMQogICkpJT4lIAogIGZpbHRlcihhYnMoZml0bmVzc19kaWZmZXJlbmNlKSA+IDAuNSkKCiMgc3BsaXQgYnkgd2lubmVyIGFuZCBsb3NlcgpzdGF0aWNfZGMubHMxIDwtIHNwbGl0KHNlbGVjdChzdGF0aWNfZGMuZGY0LCBSLCB0b3RhbCA9IHRvdGFsX3dpbm5lciksIHN0YXRpY19kYy5kZjQkaWRfYWx0KQpzdGF0aWNfZGMubHMyIDwtIHNwbGl0KHNlbGVjdChzdGF0aWNfZGMuZGY0LCBSLCB0b3RhbCA9IHRvdGFsX2xvc2VyKSwgc3RhdGljX2RjLmRmNCRpZF9hbHQpCgojIGdldCBhcmVhCnN0YXRpY193aW4uYXJlYSA8LSBjYmluZC5kYXRhLmZyYW1lKGFyZWEgPSBhcy5udW1lcmljKGxhcHBseShzdGF0aWNfZGMubHMxLCBjaGEpKSwgc3RhdHVzID0gIldpbm5lciIpCnN0YXRpY19sb3Nlci5hcmVhIDwtIGNiaW5kLmRhdGEuZnJhbWUoYXJlYSA9IGFzLm51bWVyaWMobGFwcGx5KHN0YXRpY19kYy5sczIsIGNoYSkpLCBzdGF0dXMgPSAiTG9zZXIiKQoKIyBwYWlyCnN0YXRpYy5hcmVhIDwtIGNiaW5kKHNlbGVjdChzdGF0aWNfd2luLmFyZWEsIFdpbm5lciA9IGFyZWEpLAogICAgICAgICAgICAgICAgICAgICBzZWxlY3Qoc3RhdGljX2xvc2VyLmFyZWEsIExvc2VyID0gYXJlYSkpICU+JSAKICBtdXRhdGUoY2xhc3NpZmljYXRpb24gPSBpZmVsc2UoV2lubmVyPkxvc2VyLCAiV2lubmVyIGxhcmdlciBhcmVhIiwgIkxvc2VyIGxhcmdlciBhcmVhIikpCmBgYAoKIyBwbG90IHN0YXRpYwpgYGB7cn0Kc3RhdGljX2FyZWEucGwgPC0gZ2dwYWlyZWQoc3RhdGljLmFyZWEsIGNvbmQxID0gIldpbm5lciIsIGNvbmQyID0gIkxvc2VyIiwgbGluZS5jb2xvciA9ICJjbGFzc2lmaWNhdGlvbiIsIGFscGhhID0gMC4yKSArCiAgbGFicyh4ID0gIlN0YXR1cyIsIHkgPSAiQXJlYSIsIGNvbG9yID0gIkNvbXBhcmlzb25cbihTdGF0aWMpIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJMb3NlciBsYXJnZXIgYXJlYSIgPSAiI2ZjOGQ1OSIsICJXaW5uZXIgbGFyZ2VyIGFyZWEiID0gIiM0NTc1YjQiKSkgKwogIHN0YXRfY29tcGFyZV9tZWFucyhwYWlyZWQgPSBUUlVFLCBoanVzdCA9IDApICsKICBndWlkZXMoY29sb3I9Z3VpZGVfbGVnZW5kKG5yb3c9MixieXJvdz1UUlVFKSkKYGBgCgoKIy0tLS0tLS0tLSBpbnZhc2lvbiBhcmVhIGNvbXBhcmlzb24gLS0tLS0tLS0tLS0tLS0tLS0jCiMgZ2V0IGFyZWEKYGBge3J9CiMgaW1wb3J0IGluIGRjIGR5bmFtaWMgYW5kIGZpdG5lc3MKaW52YXNpb25fZGMuZGYgPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9pbnZhc2lvbl9kYy5wYXJxdWV0IikpCmludmFzaW9uX2ZpdG5lc3MuZGYgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9jaV9pbnZhc2lvbi5jc3YiKSkKCmludmFzaW9uX2RjLmRmNCA8LSBpbnZhc2lvbl9kYy5kZiAlPiUgCiAgbGVmdF9qb2luKGludmFzaW9uX2ZpdG5lc3MuZGYsIGJ5ID0gYygibXV0X2lkIiwgInJlc19pZCIpKSAlPiUgCiAgbXV0YXRlKAogIHRvdGFsX3dpbm5lciA9IGNhc2Vfd2hlbigKICAgIGZpdG5lc3M+IDAgfiB0b3RhbDEsCiAgICBmaXRuZXNzPCAwIH4gdG90YWwyCiAgKSwKICB0b3RhbF9sb3NlciA9IGNhc2Vfd2hlbigKICAgIGZpdG5lc3MgPiAwIH4gdG90YWwyLAogICAgZml0bmVzcyA8IDAgfiB0b3RhbDEKICApKSAlPiUgCiAgZmlsdGVyKGFicyhmaXRuZXNzKSA+IDAuNSkKCiMgc3BsaXQgYnkgd2lubmVyIGFuZCBsb3NlcgppbnZhc2lvbl9kYy5sczEgPC0gc3BsaXQoc2VsZWN0KGludmFzaW9uX2RjLmRmNCwgUiwgdG90YWwgPSB0b3RhbF93aW5uZXIpLCBpbnZhc2lvbl9kYy5kZjQkaWRfYWx0KQppbnZhc2lvbl9kYy5sczIgPC0gc3BsaXQoc2VsZWN0KGludmFzaW9uX2RjLmRmNCwgUiwgdG90YWwgPSB0b3RhbF9sb3NlciksIGludmFzaW9uX2RjLmRmNCRpZF9hbHQpCgojIGdldCBhcmVhCmludmFzaW9uX3dpbi5hcmVhIDwtIGNiaW5kLmRhdGEuZnJhbWUoYXJlYSA9IGFzLm51bWVyaWMobGFwcGx5KGludmFzaW9uX2RjLmxzMSwgY2hhKSksIHN0YXR1cyA9ICJXaW5uZXIiKQppbnZhc2lvbl9sb3Nlci5hcmVhIDwtIGNiaW5kLmRhdGEuZnJhbWUoYXJlYSA9IGFzLm51bWVyaWMobGFwcGx5KGludmFzaW9uX2RjLmxzMiwgY2hhKSksIHN0YXR1cyA9ICJMb3NlciIpCgojIHBhaXIKaW52YXNpb24uYXJlYSA8LSBjYmluZChzZWxlY3QoaW52YXNpb25fd2luLmFyZWEsIFdpbm5lciA9IGFyZWEpLAogICAgICAgICAgICAgICAgICAgICBzZWxlY3QoaW52YXNpb25fbG9zZXIuYXJlYSwgTG9zZXIgPSBhcmVhKSkgJT4lIAogIG11dGF0ZShjbGFzc2lmaWNhdGlvbiA9IGlmZWxzZShXaW5uZXI+TG9zZXIsICJXaW5uZXIgbGFyZ2VyIGFyZWEiLCAiTG9zZXIgbGFyZ2VyIGFyZWEiKSkKYGBgCgojIHBsb3QKYGBge3J9CmludmFzaW9uX2FyZWEucGwgPC1nZ3BhaXJlZChpbnZhc2lvbi5hcmVhLCBjb25kMSA9ICJXaW5uZXIiLCBjb25kMiA9ICJMb3NlciIsIGxpbmUuY29sb3IgPSAiY2xhc3NpZmljYXRpb24iLCBhbHBoYSA9IDAuMikgKwogIGxhYnMoeCA9ICJTdGF0dXMiLCB5ID0gIkFyZWEiLCBjb2xvciA9ICJDb21wYXJpc29uXG4oSW52YXNpdmUpIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJMb3NlciBsYXJnZXIgYXJlYSIgPSAiI2ZjOGQ1OSIsICJXaW5uZXIgbGFyZ2VyIGFyZWEiID0gIiM0NTc1YjQiKSkgKwogIHN0YXRfY29tcGFyZV9tZWFucyhwYWlyZWQgPSBUUlVFLCBoanVzdCA9IDApICsKICBndWlkZXMoY29sb3I9Z3VpZGVfbGVnZW5kKG5yb3c9MixieXJvdz1UUlVFKSkKICAKYGBgCgojLS0tLS0tIHBsb3QgdG9nZXRoZXIgLS0tLS0tLS0tLS0tLSMKYGBge3J9CiMgcGFpcndpc2UgY29tcGFyaXNvbiBmb3Igc3RhdGljIGFuZCBpbnZhc2l2ZSBjb21lcHRpdGlvbgpoZXRlcm9jdWVfY29tcC5wbCA8LSBnZ2FycmFuZ2Uoc3RhdGljX2FyZWEucGwsIGludmFzaW9uX2FyZWEucGwsIG5jb2wgPSAyLCBucm93ID0gMSwgYWxpZ24gPSAidiIpCgojIGpvaW4gaW50aGUgb3RoZXIgZGlzZWFzZSBjdXJ2ZXMKZ2dhcnJhbmdlKHNpX3Zpci5wbCwgY2lfdmlyLnBsLCBkdWFsX3Zpci5wbCwgaGV0ZXJvY3VlX2NvbXAucGwsIG5jb2wgPSAyLCBucm93ID0gMiwgbGFiZWxzID0gYygiQSIsICJCIiwgIkMiLCAiRCIpLCBoZWlnaHRzID0gYygxLCAwLjgpKQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vdmlydWxlbmNlLnRpZmYiKSwgdW5pdHMgPSAicHgiLCB3aWR0aCA9IDIyNTAsIGhlaWdodCA9IDE2MDAsIHNjYWxlID0gMiwgZHBpPTMwMCwgYmcgPSAid2hpdGUiKQpgYGAKCgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwojIGR1YWwgY3VlIGR5bmFtaWNzIGZpZ3VyZQojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCgojIGdldCBkdWFsIGR5bmFtaWNzCmBgYHtyfQpkdWFsLmR5biA8LSBjaGFiYXVkaV9zaV9jbGVhbigKICBwYXJhbWV0ZXJzX2NyID0gYyg0LjQ0NjE5MjAzMywJMTAuOTc1MTgyNzUsCTEuMzg3NjI4MTcsCTIzLjMwNTkyNTQsCS0zLjQ1MjA1MjM3MSwJLTE4LjAwNzA2OTIsCTM5LjY2NjE0MjI2LAktMy41NDUxOTMxNDEsCTE4Ljc4MzUwNzk5KSwKICBpbW11bml0eSA9ICJ0c3VrdXNoaSIsCiAgcGFyYW1ldGVycyA9IHBhcmFtZXRlcnNfdHN1a3VzaGksCiAgdGltZV9yYW5nZSA9IHNlcSgwLCAzMCwgYnkgPSAxZS0zKSwKICBjdWVfcmFuZ2UgPSAgc2VxKDYsIDcsIGJ5ID0gMS81MDApLAogIGN1ZV9yYW5nZV9iID0gc2VxKDAsIGxvZzEwKDYqKDEwXjYpKSwgYnkgPSAobG9nMTAoNiooMTBeNikpKS81MDApLAogIGN1ZSA9ICJSIiwKICBjdWVfYiA9ICJJIiwKICBsb2dfY3VlID0gImxvZzEwIiwKICBsb2dfY3VlX2IgPSAibG9nMTAiLAogIHNvbHZlciA9ICJ2b2RlIiwKICBkeW4gPSBUCikKCiMgZmlsdGVyIG91dCByZWxldmVudCBkYXRhZnJhbWVzCmR1YWwuZHluX2YgPC0gZHVhbC5keW4gJT4lIAogIGZpbHRlcih2YXJpYWJsZSAlaW4lIGMoIkkiLCAiSWciLCAiRyIsICJSIiwgIk4iLCAiVyIpKQoKIyBjciBvbmx5CmR1YWwuZHluX2NyIDwtIGR1YWwuZHluICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gImNyIikKYGBgCgojIHBsb3QKYGBge3J9CmR1YWxfSS5wbHQgPC0gZ2dwbG90KCkgKwogIGdlb21fbGluZShkYXRhID0gZHVhbC5keW5fZiAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJJIiksIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlLygxMF41KSksCiAgICAgICAgICAgIGNvbG9yID0gIiM0NTc1YjQiKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZHVhbC5keW5fZiAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJJIiAmIHJvd19udW1iZXIoKSAlJSAxMDAwID09IDApLCAKICAgICAgICAgICAgIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlLygxMF41KSksIHNpemUgPSAyLCBjb2xvciA9ICIjNDU3NWI0IikgKwogIGdlb21fbGluZShkYXRhID0gZHVhbC5keW5fY3IsIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlKSkgKwogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIkNvbnZlcnNpb24gcmF0ZSIsCiAgICAgICAgICAgICAgICAgICAgIHNlYy5heGlzID0gc2VjX2F4aXMofi4qMTBeNSwgbmFtZT0iQXNleHVhbCBpUkJDIHBlciDCtUwiKSkgKwogIGxhYnMoeCA9ICJUaW1lIChkYXlzKSIpICsKICB4bGltKDAsIDIwKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKZHVhbF9JZy5wbHQgPC1nZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBkdWFsLmR5bl9mICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gIklnIiksIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlLygxMF41KSksCiAgICAgICAgICAgIGNvbG9yID0gIiM0NTc1YjQiKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZHVhbC5keW5fZiAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJJZyIgJiByb3dfbnVtYmVyKCkgJSUgMTAwMCA9PSAwKSwgCiAgICAgICAgICAgICBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZS8oMTBeNSkpLCBzaXplID0gMiwgY29sb3IgPSAiIzQ1NzViNCIpICsKICBnZW9tX2xpbmUoZGF0YSA9IGR1YWwuZHluX2NyLCBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobmFtZSA9ICJDb252ZXJzaW9uIHJhdGUiLAogICAgICAgICAgICAgICAgICAgICBzZWMuYXhpcyA9IHNlY19heGlzKH4uKjEwXjUsIG5hbWU9IlNleHVhbCBpUkJDIHBlciDCtUwiKSkgKwogIGxhYnMoeCA9ICJUaW1lIChkYXlzKSIpICsKICB4bGltKDAsIDIwKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKZHVhbF9HLnBsdCA8LWdncGxvdCgpICsKICBnZW9tX2xpbmUoZGF0YSA9IGR1YWwuZHluX2YgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiRyIpLCBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZS8oMTBeNCkpLAogICAgICAgICAgICBjb2xvciA9ICIjNDU3NWI0IikgKwogIGdlb21fcG9pbnQoZGF0YSA9IGR1YWwuZHluX2YgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiRyIgJiByb3dfbnVtYmVyKCkgJSUgMTAwMCA9PSAwKSwgCiAgICAgICAgICAgICBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZS8oMTBeNCkpLCBzaXplID0gMiwgY29sb3IgPSAiIzQ1NzViNCIpICsKICBnZW9tX2xpbmUoZGF0YSA9IGR1YWwuZHluX2NyLCBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobmFtZSA9ICJDb252ZXJzaW9uIHJhdGUiLAogICAgICAgICAgICAgICAgICAgICBzZWMuYXhpcyA9IHNlY19heGlzKH4uKjEwXjQsIG5hbWU9IkdhbWV0b2N5dGUgcGVyIMK1TCIpKSArCiAgbGFicyh4ID0gIlRpbWUgKGRheXMpIikgKwogIHhsaW0oMCwgMjApICsKICB0aGVtZV9idygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpkdWFsX1IucGx0IDwtZ2dwbG90KCkgKwogIGdlb21fbGluZShkYXRhID0gZHVhbC5keW5fZiAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJSIiksIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlLygxMF43KSksCiAgICAgICAgICAgIGNvbG9yID0gIiM0NTc1YjQiKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZHVhbC5keW5fZiAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJSIiAmIHJvd19udW1iZXIoKSAlJSAxMDAwID09IDApLCAKICAgICAgICAgICAgIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlLygxMF43KSksIHNpemUgPSAyLCBjb2xvciA9ICIjNDU3NWI0IikgKwogIGdlb21fbGluZShkYXRhID0gZHVhbC5keW5fY3IsIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlKSkgKwogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIkNvbnZlcnNpb24gcmF0ZSIsCiAgICAgICAgICAgICAgICAgICAgIHNlYy5heGlzID0gc2VjX2F4aXMofi4qMTBeNywgbmFtZT0iUkJDIHBlciDCtUwiKSkgKwogIGxhYnMoeCA9ICJUaW1lIChkYXlzKSIpICsKICB4bGltKDAsIDIwKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKZHVhbF9OLnBsdCA8LWdncGxvdCgpICsKICBnZW9tX2xpbmUoZGF0YSA9IGR1YWwuZHluX2YgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiTiIpLCBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZSoxMCksCiAgICAgICAgICAgIGNvbG9yID0gIiM0NTc1YjQiKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZHVhbC5keW5fZiAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJOIiAmIHJvd19udW1iZXIoKSAlJSAxMDAwID09IDApLCAKICAgICAgICAgICAgIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlKjEwKSwgc2l6ZSA9IDIsIGNvbG9yID0gIiM0NTc1YjQiKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBkdWFsLmR5bl9jciwgYWVzKHggPSB0aW1lLCB5ID0gdmFsdWUpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKG5hbWUgPSAiQ29udmVyc2lvbiByYXRlIiwKICAgICAgICAgICAgICAgICAgICAgc2VjLmF4aXMgPSBzZWNfYXhpcyh+LiowLjEsIG5hbWU9IkluZGlzY3JpbWluYXRlIGltbXVuaXR5IikpICsKICBsYWJzKHggPSAiVGltZSAoZGF5cykiKSArCiAgeGxpbSgwLCAyMCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCmR1YWxfVy5wbHQgPC1nZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBkdWFsLmR5bl9mICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gIlciKSwgYWVzKHggPSB0aW1lLCB5ID0gdmFsdWUqMiksCiAgICAgICAgICAgIGNvbG9yID0gIiM0NTc1YjQiKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZHVhbC5keW5fZiAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJXIiAmIHJvd19udW1iZXIoKSAlJSAxMDAwID09IDApLCAKICAgICAgICAgICAgIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlKjIpLCBzaXplID0gMiwgY29sb3IgPSAiIzQ1NzViNCIpICsKICBnZW9tX2xpbmUoZGF0YSA9IGR1YWwuZHluX2NyLCBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobmFtZSA9ICJDb252ZXJzaW9uIHJhdGUiLAogICAgICAgICAgICAgICAgICAgICBzZWMuYXhpcyA9IHNlY19heGlzKH4uKjAuNSwgbmFtZT0iVGFyZ2V0ZWQgaW1tdW5pdHkiKSkgKwogIGxhYnMoeCA9ICJUaW1lIChkYXlzKSIpICsKICB4bGltKDAsIDIwKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCiMgcGxvdCB0b2dldGhlcgpgYGB7cn0KZ2dhcnJhbmdlKGR1YWxfSS5wbHQsIGR1YWxfSWcucGx0LCBkdWFsX0cucGx0LCBkdWFsX1IucGx0LCBkdWFsX04ucGx0LCBkdWFsX1cucGx0LCBucm93ID0gMywgbmNvbCA9IDIsIGFsaWduID0gImh2IiwgbGFiZWxzID0gYygiQSIsICJCIiwgIkMiLCAiRCIsICJFIiwgIkYiKSkKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vZHVhbF9keW4udGlmZiIpLCB1bml0cyA9ICJweCIsIHdpZHRoID0gMjI1MCwgaGVpZ2h0ID0gMjAwMCwgc2NhbGUgPSAxLCBkcGk9MzAwLCBiZyA9ICJ3aGl0ZSIpCmBgYAoKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwojIFNpbmdsZSBhbmQgY28taW5mZWN0aW9uIHZlcmlmaWNhdGlvbgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMgc2luZ2xlIGluZmVjdGlvbgpgYGB7cn0KIyBpbXBvcnQgaW4gYWxsIHNpbmdsZSBpbmZlY3Rpb24gZGF0YQpzaV92YWwubHMgPC0gbGlzdC5maWxlcyhwYXRoID0gaGVyZSgiZGF0YS9zaV92YWxpZGF0aW9uIiksIHBhdHRlcm4gPSAiKi5jc3YiLCBmdWxsLm5hbWVzID0gVCkKCnNpX3ZhbC5kZiA8LSBsYXBwbHkoc2lfdmFsLmxzLCByZWFkLmNzdikKc2lfdmFsLmRmIDwtIGRvLmNhbGwocmJpbmQsIHNpX3ZhbC5kZikKCiMgZ2V0IG1heCBmaXRuZXNzIGZyb20gc2ltdWxhdGlvbi4gbGVmdCBqb2luIHdpdGggc2lfb3B0CnNpX29wdC5kZiA8LSByZWFkLmNzdihoZXJlKCJkYXRhL3NpX29wdC5jc3YiKSkKCiMgd2UgY2FuIHNlZSB0aGF0IGFsbCBvZiB0aGUgcmFuZG9tbHkgc2ltdWxhdGVkIG1vZGVscyBoYXZlIGEgZml0bmVzcyB2YWx1ZSB0aGF0IGlzIGxlc3MgdGhhbiB0aGUgb3B0aW1pemVkIG1vZGVsCnNpX3ZhbC5kZjIgPC0gc2VsZWN0KHNpX3ZhbC5kZiwgVjEsIGlkKSAlPiUKICBsZWZ0X2pvaW4oc2lfb3B0LmRmLCBieSA9YygiaWQiID0gImlkIikpICU+JSAKICBtdXRhdGUoZml0bmVzc19kaWZmZXJlbmNlID0gZml0bmVzc18yMCAtIFYxKSAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChlel9sYWJlbCwgaWRfc2ksIGV6X2xhYmVsX3NpKSwgYnkgPSBjKCJpZCIgPSAiaWRfc2kiKSkKYGBgCgojIyMgTW9kZWwgdmFsaWRhdGlvbgpgYGB7cn0KIyByZWFkIGluIHRoZSByZXN1bHRzIGZpbGUKY2lfdmFsLmxzIDwtIGxpc3QuZmlsZXMocGF0aCA9IGhlcmUoImRhdGEvY2lfdmFsaWRhdGlvbiIpLCBwYXR0ZXJuID0gIiouY3N2IiwgZnVsbC5uYW1lcyA9IFQpCmNpX3ZhbC5sczIgPC0gbGFwcGx5KGNpX3ZhbC5scywgcmVhZC5jc3YpCmNpX3ZhbC5kZiA8LSBkby5jYWxsKHJiaW5kLCBjaV92YWwubHMyKQoKY2lfdmFsLmRmMgpjaV92YWwuZGYyIDwtIGNpX3ZhbC5kZiAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChlel9sYWJlbCwgbGFiZWxfY2ksIGV6X2xhYmVsKSwgYnkgPSBjKCJsYWJlbCIgPSAibGFiZWxfY2kiKSkKYGBgCgojIHBsb3QKYGBge3J9CnNpX3ZhbC5wbHQgPC0gZ2dwbG90KGRhdGEgPSBzaV92YWwuZGYyLCBhZXMoeCA9IGZpdG5lc3NfZGlmZmVyZW5jZSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gNTApICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICIjZmM4ZDU5IikgKwogIGZhY2V0X3dyYXAofmV6X2xhYmVsX3NpLCBzY2FsZXMgPSAiZnJlZSIsIG5jb2wgPSAzKSArCiAgbGFicyh4ID0gIk9wdGltaXplZCBmaXRuZXNzIC0gcmFuZG9tIGZpdG5lc3MiLCB5ID0gIkZyZXF1ZW5jeSIpICsKICB0aGVtZV9idygpCgpjaV92YWwucGx0IDwtIGdncGxvdChkYXRhID0gY2lfdmFsLmRmMiwgYWVzKHggPSBWMSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gNTApICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICIjZmM4ZDU5IikgKwogIGZhY2V0X3dyYXAofmV6X2xhYmVsLCBzY2FsZXMgPSAiZnJlZSIsIG5jb2wgPSA0KSArCiAgbGFicyh4ID0gIkZpdG5lc3MgZGlmZmVyZW5jZSBiZXR3ZWVuXG5vcHRpbWl6ZWQgYW5kIHJhbmRvbSBzdHJhaW4iLCB5ID0gIkZyZXF1ZW5jeSIpICsKICB0aGVtZV9idygpCgpnZ2FycmFuZ2Uoc2lfdmFsLnBsdCwgY2lfdmFsLnBsdCwgYWxpZ24gPSAiaHYiLCBsYWJlbHMgPSBjKCJBIiwgIkIiKSwgd2lkdGhzID0gYygzLDQpKQpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby92YWxpZGF0aW9uLnRpZmYiKSwgdW5pdHMgPSAicHgiLCB3aWR0aCA9IDIyNTAsIGhlaWdodCA9IDEzMDAsIHNjYWxlID0gMS42LCBkcGk9MzAwLCBiZyA9ICJ3aGl0ZSIpCmBgYAoKIz09PT09PT09PT09PT09PT09PT09PT09PT0jCiMgTW9udGUgY2FybG8gZHluYW1pY3Mgc3VwcGxlbWVudGFyeQojPT09PT09PT09PT09PT09PT09PT09PT09PSMKIyBydW4gY29kZSBpbiByZXBvcnQgMTYKYGBge3J9Cm1jX2R5bl9hIDwtIGdncGxvdCgpICsKICBnZW9tX2xpbmUoZGF0YSA9IHJlZmVyZW5jZS5kZiwgYWVzKHggPSB0aW1lLCB5ID0gY3IpKSArCiAgZ2VvbV9yaWJib24oZGF0YSA9IGRpZmYuZGYsIGFlcyh4ID0gdGltZSwgeW1pbiA9IGNyX2JvdCwgeW1heCA9IGNyX3RvcCksIGFscGhhID0gMC41LCBmaWxsID0gIiNmYzhkNTkiKSArCiAgZmFjZXRfd3JhcCh+Y3VlLCBuY29sID0gMikgKwogIGxhYnMoeCA9ICJUaW1lIChkYXlzKSIsIHkgPSAiQ29udmVyc2lvbiByYXRlIikgKwogIHRoZW1lX2J3KCkKICAKIyBwbG90IGZpdG5lc3MgdGltZXNlcmllcy4gV2hlbiBpZiB0aW5lc3MgbG9zdD8gQXQgdGhlIGxhdHRlciBwYXJ0Cm1jX2R5bl9iICA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSByZWZlcmVuY2UuZGYsIGFlcyh4ID0gdGltZSwgeSA9IHRhdSkpICsKICBnZW9tX3JpYmJvbihkYXRhID0gZGlmZi5kZiwgYWVzKHggPSB0aW1lLCB5bWluID0gdGF1X2JvdCwgeW1heCA9IHRhdV90b3ApLCBhbHBoYSA9IDAuNSwgZmlsbCA9ICIjZmM4ZDU5IikgKwogIGZhY2V0X3dyYXAofmN1ZSwgbmNvbCA9IDIpICsKICBsYWJzKHggPSAiVGltZSAoZGF5cykiLCB5ID0gIlRyYW5zbWlzc2lvbiBwb3RlbnRpYWwiKSArCiAgdGhlbWVfYncoKQoKZ2dhcnJhbmdlKG1jX2R5bl9hLCBtY19keW5fYiwgbmNvbCA9IDEsIGFsaWduID0gInYiLCBsYWJlbHMgPSBjKCJBIiwgIkIiKSkKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vTUNfZHluLnRpZmYiKSwgdW5pdHMgPSAicHgiLCB3aWR0aCA9IDIwMDAsIGhlaWdodCA9IDI2MDAsIHNjYWxlID0gMSwgZHBpPTMwMCwgYmcgPSAid2hpdGUiKQpgYGAKCgoK